npm install @auth0/angular-jwt
import { JwtModule } from '@auth0/angular-jwt';
export function tokenGetter() {
return localStorage.getItem('access_token');
}
@NgModule({
imports: [
JwtModule.forRoot({
config: {
tokenGetter: tokenGetter,
allowedDomains: ['api.example.com'],
disallowedRoutes: ['api.example.com/auth/login']
}
})
]
})
export class AuthModule {}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class AuthService {
private readonly loginUrl = '/api/auth/login';
constructor(private http: HttpClient) {}
login(credentials: {email: string, password: string}) {
return this.http.post<{token: string}>(this.loginUrl, credentials).pipe(
tap(res => {
localStorage.setItem('access_token', res.token);
})
);
}
logout() {
localStorage.removeItem('access_token');
}
isLoggedIn(): boolean {
return !!localStorage.getItem('access_token');
}
getToken(): string | null {
return localStorage.getItem('access_token');
}
}
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import { AuthService } from './auth.service';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private auth: AuthService) {}
intercept(request: HttpRequest<unknown>, next: HttpHandler) {
const token = this.auth.getToken();
if (token) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
return next.handle(request);
}
}
Не забудьте зарегистрировать интерсептор в модуле:
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true }
]
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) {}
canActivate(): boolean {
if (this.auth.isLoggedIn()) {
return true;
}
this.router.navigate(['/login']);
return false;
}
}
Использование в роутинге:
{
path: 'profile',
component: ProfileComponent,
canActivate: [AuthGuard]
}
Добавьте в интерсептор проверку 401 ошибки:
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
catchError(err => {
if (err.status === 401) {
this.auth.logout();
this.router.navigate(['/login']);
}
return throwError(err);
})
);
}
private refreshToken() {
return this.http.post<{token: string}>('/api/auth/refresh', {
refreshToken: localStorage.getItem('refresh_token')
}).pipe(
tap(res => {
localStorage.setItem('access_token', res.token);
})
);
}
// В интерсепторе:
if (err.status === 401 && !request.url.includes('/auth/refresh')) {
return this.auth.refreshToken().pipe(
switchMap(() => {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${this.auth.getToken()}`
}
});
return next.handle(request);
}),
catchError(() => {
this.auth.logout();
this.router.navigate(['/login']);
return throwError('Session expired');
})
);
}
Установите пакет:
npm install jwt-decode
Использование:
import jwt_decode from 'jwt-decode';
getUserInfo(): any {
const token = this.getToken();
if (token) {
return jwt_decode(token);
}
return null;
}
isTokenExpired(): boolean {
const token = this.getToken();
if (!token) return true;
const date = this.getTokenExpirationDate(token);
if (date === undefined) return false;
return !(date.valueOf() > new Date().valueOf());
}
localStorage
или sessionStorage
Реализация JWT в Angular требует создания сервиса аутентификации, HTTP интерсептора и route guards. Важно правильно обрабатывать истечение токена и соблюдать меры безопасности. Использование библиотеки @auth0/angular-jwt значительно упрощает интеграцию.