Аутентификация
Система аутентификации в Integ Admin основана на JWT токенах с поддержкой refresh tokens.
Обзор
Аутентификация включает в себя:
- ✅ Вход по email и паролю
- ✅ Регистрация новых пользователей
- ✅ JWT access и refresh токены
- ✅ Автоматическое добавление токена к запросам
- ✅ Защита маршрутов через guards
- ✅ Автоматический logout при 401
Архитектура
┌─────────────┐
│ User │
└──────┬──────┘
│
▼
┌─────────────────┐ ┌──────────────┐
│ Login Page │────▶│ AuthService │
└─────────────────┘ └──────┬───────┘
│
▼
┌─────────────┐
│ API │
│ /auth/* │
└──────┬──────┘
│
▼
┌─────────────┐
│ localStorage│
│ - access_token
│ - refresh_token
└─────────────┘Функциональность
Вход в систему
Страница: /auth/login
- Пользователь вводит email и пароль
- Отправка запроса
POST /auth/sign-in - Получение access и refresh токенов
- Сохранение токенов в localStorage
- Редирект на
/admin/dashboard
Пример кода:
@Component({
selector: "app-login",
standalone: true,
imports: [ReactiveFormsModule, MatFormFieldModule, MatInputModule],
templateUrl: "./login.component.html"
})
export class LoginComponent {
private readonly authService = inject(AuthService);
private readonly router = inject(Router);
loginForm = new FormGroup({
email: new FormControl("", [Validators.required, Validators.email]),
password: new FormControl("", [Validators.required])
});
onSubmit() {
if (this.loginForm.valid) {
const { email, password } = this.loginForm.value;
this.authService.login(email!, password!).subscribe({
next: () => {
this.router.navigate(["/admin/dashboard"]);
},
error: (error) => {
console.error("Login failed:", error);
}
});
}
}
}Регистрация
Страница: /auth/register
- Пользователь заполняет форму регистрации
- Отправка запроса
POST /auth/sign-up - Автоматический вход после успешной регистрации
Выход из системы
Выход происходит при:
- Нажатии кнопки "Выход"
- Получении 401 ошибки
- Истечении токена
logout() {
this.authService.logout();
// Токены удаляются
// Редирект на /auth/login
}AuthService API
Методы
login(email: string, password: string): Observable<void>
Выполняет вход пользователя.
this.authService.login("user@example.com", "password123").subscribe(() => {
console.log("Успешный вход");
});logout(): void
Выполняет выход и редирект.
this.authService.logout();me(): Observable<IUser>
Получает информацию о текущем пользователе.
this.authService.me().subscribe((user) => {
console.log(user.email);
});isAuthenticated: boolean
Проверка авторизации.
if (this.authService.isAuthenticated) {
// Пользователь авторизован
}isAuthenticated$: Observable<boolean>
Observable для реактивной проверки авторизации.
this.authService.isAuthenticated$.subscribe((isAuth) => {
this.showAdminPanel = isAuth;
});Guards
authGuard
Защищает маршруты, требующие авторизации.
Использование:
const routes: Routes = [
{
path: "admin",
canActivate: [authGuard],
loadComponent: () => import("./admin.component")
}
];Логика:
export const authGuard: CanActivateFn = () => {
const authService = inject(AuthService);
const router = inject(Router);
if (!authService.isAuthenticated) {
return router.createUrlTree(["/auth/login"]);
}
return true;
};noAuthGuard
Редиректит авторизованных пользователей (для страниц login/register).
Использование:
const routes: Routes = [
{
path: "auth/login",
canActivate: [noAuthGuard],
loadComponent: () => import("./login.component")
}
];Interceptors
Auth Interceptor
Автоматически добавляет JWT токен ко всем запросам.
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const token = localStorage.getItem("access_token");
if (token) {
req = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
return next(req);
};Error Interceptor
Обрабатывает 401 ошибки и выполняет logout.
export const errorInterceptor: HttpInterceptorFn = (req, next) => {
const authService = inject(AuthService);
return next(req).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 401) {
authService.logout();
}
return throwError(() => error);
})
);
};Хранение токенов
Токены хранятся в localStorage:
// Ключи
ACCESS_TOKEN_KEY = "access_token";
REFRESH_TOKEN_KEY = "refresh_token";
// Сохранение
localStorage.setItem("access_token", token);
// Получение
const token = localStorage.getItem("access_token");
// Удаление
localStorage.removeItem("access_token");SSR
Код использует isPlatformBrowser для проверки окружения перед работой с localStorage, что необходимо для корректной работы SSR.
JWT Claims
Токен можно декодировать для получения claims:
import { jwtDecode } from "jwt-decode";
const claims = this.authService.getTokenClaims();
// claims содержит: userId, email, exp, iat и т.д.Безопасность
Best Practices
✅ Что делается:
- Токены в localStorage (не в cookies)
- HTTPS обязателен для production
- Токены автоматически прикрепляются к запросам
- Автоматический logout при 401
❌ Что НЕ делается:
- XSS защита — ответственность разработчика
- CSRF — не применимо при использовании JWT без cookies
Рекомендации
- Всегда используйте HTTPS в production
- Устанавливайте короткое время жизни access токена
- Используйте refresh токен для обновления
- Валидируйте токены на backend'е
API Endpoints
| Метод | Endpoint | Описание |
|---|---|---|
| POST | /auth/sign-in | Вход в систему |
| POST | /auth/sign-up | Регистрация |
| GET | /auth/me | Получить текущего пользователя |
| POST | /auth/refresh | Обновить токен (если реализовано) |
Следующие шаги
- Интеграции — управление интеграциями
- Access Tokens — токены для API
- API Reference — документация AuthService