protected-route-fix
All checks were successful
Deploy on push / deploy (push) Successful in 3m2s

This commit is contained in:
2025-09-29 15:54:22 +03:00
parent 8e944e399a
commit f2398d3592
4 changed files with 114 additions and 16 deletions

View File

@@ -76,13 +76,19 @@ export const AuthProvider: Component<AuthProviderProps> = (props) => {
// Инициализация авторизации при монтировании
onMount(async () => {
console.log('[AuthProvider] Performing auth initialization...')
// 🍪 Для httpOnly cookies проверяем авторизацию через GraphQL запрос
try {
console.log('[AuthProvider] Checking authentication via GraphQL...')
// Делаем тестовый запрос для проверки авторизации
const result = await query<{ me: { id: string } | null }>(`${location.origin}/graphql`, `
// Добавляем таймаут для запроса
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Auth check timeout')), 10000)
)
const authPromise = query<{ me: { id: string } | null }>(
`${location.origin}/graphql`,
`
query CheckAuth {
me {
id
@@ -90,8 +96,14 @@ export const AuthProvider: Component<AuthProviderProps> = (props) => {
email
}
}
`)
`
)
// Делаем тестовый запрос для проверки авторизации с таймаутом
const result = (await Promise.race([authPromise, timeoutPromise])) as {
me: { id: string; name: string; email: string } | null
}
if (result?.me?.id) {
console.log('[AuthProvider] User authenticated via httpOnly cookie:', result.me.id)
setIsAuthenticated(true)
@@ -102,10 +114,11 @@ export const AuthProvider: Component<AuthProviderProps> = (props) => {
} catch (error) {
console.log('[AuthProvider] Authentication check failed:', error)
setIsAuthenticated(false)
} finally {
// Всегда устанавливаем ready в true, даже при ошибке
console.log('[AuthProvider] Auth initialization complete, ready for requests')
setIsReady(true)
}
console.log('[AuthProvider] Auth initialization complete, ready for requests')
setIsReady(true)
})
const login = async (username: string, password: string) => {

View File

@@ -177,6 +177,81 @@ body {
}
}
/* Auth Error Screen */
.auth-error-screen {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: var(--background-color);
padding: 2rem;
}
.auth-error-content {
text-align: center;
max-width: 500px;
padding: 2rem;
background-color: var(--card-background);
border-radius: var(--border-radius);
border: 1px solid var(--border-color);
box-shadow: var(--shadow-sm);
}
.auth-error-content h2 {
color: var(--danger-color);
font-size: var(--font-size-xl);
margin-bottom: 1rem;
font-weight: 600;
}
.auth-error-content p {
color: var(--text-color-light);
font-size: var(--font-size-base);
margin-bottom: 2rem;
line-height: 1.6;
}
.auth-error-actions {
display: flex;
flex-direction: column;
gap: 1rem;
}
.auth-error-actions .btn {
padding: 0.75rem 1.5rem;
border-radius: var(--border-radius);
border: none;
font-size: var(--font-size-base);
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
text-decoration: none;
display: inline-block;
}
.auth-error-actions .btn-primary {
background-color: var(--primary-color);
color: white;
}
.auth-error-actions .btn-primary:hover {
background-color: var(--primary-color-dark);
transform: translateY(-1px);
}
.auth-error-actions .btn-secondary {
background-color: transparent;
color: var(--text-color-light);
border: 1px solid var(--border-color);
}
.auth-error-actions .btn-secondary:hover {
background-color: var(--hover-color);
border-color: var(--primary-color);
color: var(--text-color);
}
.error-message {
background-color: var(--danger-light);
border-left: 4px solid var(--danger-color);

View File

@@ -29,9 +29,19 @@ export const ProtectedRoute = () => {
<Show
when={auth.isAuthenticated()}
fallback={
<div class="loading-screen">
<div class="loading-spinner" />
<div>Перенаправление на страницу входа...</div>
<div class="auth-error-screen">
<div class="auth-error-content">
<h2>Доступ запрещен</h2>
<p>У вас нет прав доступа к админ-панели или ваша сессия истекла.</p>
<div class="auth-error-actions">
<button class="btn btn-primary" onClick={() => (window.location.href = '/login')}>
Войти в аккаунт
</button>
<button class="btn btn-secondary" onClick={() => auth.logout()}>
Выйти из текущего аккаунта
</button>
</div>
</div>
</div>
}
>

View File

@@ -4,8 +4,8 @@
*/
// Экспортируем константы для использования в других модулях
export const AUTH_TOKEN_KEY = 'auth_token' // localStorage fallback
export const SESSION_COOKIE_NAME = 'session_token' // ✅ httpOnly cookie от backend
export const AUTH_TOKEN_KEY = 'auth_token' // localStorage fallback
export const SESSION_COOKIE_NAME = 'session_token' // ✅ httpOnly cookie от backend
export const CSRF_TOKEN_KEY = 'csrf_token'
/**
@@ -99,6 +99,6 @@ export function checkAuthStatus(): boolean {
// Реальная проверка авторизации произойдет при первом GraphQL запросе
// Если cookie недействителен, backend вернет ошибку авторизации
console.log('[Auth] Using httpOnly cookie authentication - status will be verified by backend')
return true // ✅ Полагаемся на httpOnly cookie + backend проверку
return true // ✅ Полагаемся на httpOnly cookie + backend проверку
}