我如何保护 Angular 中的路线?
How can I guard routes in Angular?
目前,登录后我可以将 JWT 获取到前端。我的应用程序目前有一个登录页面作为登录页面,一旦用户登录,路由就会检查身份验证以重定向到受保护的主路径。
我的第一直觉是从后端 (Django) 发送一个布尔值并使用它来创建一个守卫。但我一直看到在前端处理这个问题似乎是更好的做法。
我所做的是创建一个 auth.service.ts 和一个 auth.guard.ts。在该服务中,我尝试从浏览器中检索令牌,然后验证它是否已过期。然后我在守卫上调用该方法,return 是一个布尔值。问题是每次我在本地存储中查找令牌时,我都会返回 null。
有没有更好的方法来实现这个目标?
auth.guard.ts
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
Router,
RouterStateSnapshot,
UrlTree,
} from '@angular/router';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
):
| Observable<boolean | UrlTree>
| Promise<boolean | UrlTree>
| boolean
| UrlTree {
console.log(this.authService.isAuthenticated());
if(!this.authService.isAuthenticated()){
this.router.navigate(['/login']);
return false;
}
return true;
}
}
auth.service.ts
import { Injectable } from '@angular/core';
import { JwtHelperService } from '@auth0/angular-jwt';
@Injectable({
providedIn: 'root'
})
export class AuthService {
public jwtHelper: JwtHelperService = new JwtHelperService();
constructor() { }
isAuthenticated(){
const jwt = localStorage.getItem('token');
return !this.jwtHelper.isTokenExpired(jwt!);
}
}
app-routing.module.ts
...
import { AuthGuard } from './user/services/auth.guard'
const routes: Routes = [
{
path: '',
component: LandingComponent,
children: [
{ path: '', component: HomeComponent, canActivate: [AuthGuard],},
{ path: 'home', component: HomeComponent, canActivate: [AuthGuard],},
{
path: 'cohort-charts',
component: CohortChartsComponent,
children: [
{ path: 'selection', component: CohortSelectionComponent },
{ path: 'edit', component: CohortEditComponent },
{ path: '', redirectTo: 'selection', pathMatch: 'full' },
],
},
],
},
{
path: 'login',
component: LoginComponent,
},
{ path: '**', redirectTo: '' },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
我想每次你在本地存储中查找令牌时,你都会返回 null 因为你没有保存令牌,或者如果你这样做,你试图将令牌存储为 object,而不是序列化(作为字符串,对其进行字符串化),所以它不会存储,或者当你得到它时,你不会传递它.
无论如何,我想 管理整个 jwt/authentification 部分的最佳做法是使用拦截器:
而 Interceptor 是一项服务,它 拦截 您所有的 http 调用,您可以设置它自动执行某些操作(例如,编辑 jwt)。
有关如何添加和更新 headers 以及如何使用拦截器拦截请求和响应的更多信息:
https://angular.io/guide/http#adding-and-updating-headers
https://angular.io/guide/http#intercepting-requests-and-responses
我让你瞥见你是如何做的/你需要什么:
- 提供 Angular 拦截器
app.module.ts:
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: HttpJwtAuthInterceptor,
multi: true,
},
{ provide: BASE_PATH, useValue: environment.apiUrl },
],
- 首先,在您的 auth.service.ts 中,store/get 令牌
的 2 种方法
// STORE the token in localstore:
setToken(token:string){
// First, serialize it (but just if token is not string type).
const tokenString:string = JSON.stringify( token );
localStorage.setItem('token', tokenString);
}
// READ the token from localstorage and Deserialize
getToken(): string | null{
let token = localStorage.getItem( 'token' );
if( token !=null){
// You just need to parse if you serialized it inside setToken() method
token = JSON.parse(carItemsString);
}
return token;
}
- 然后,在你的拦截器中:
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
} from '@angular/common/http';
import { AuthService } from '../_services/auth.service';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const url="\yourAPI\endpoint";
// Get your token
cont myToken = this.authService.getToken();
// Add authorization header with token if available
if (myToken) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${myToken}`,
'Content-Type': 'application/json',
},
url,
});
}
…
return next.handle(request);
}
目前,登录后我可以将 JWT 获取到前端。我的应用程序目前有一个登录页面作为登录页面,一旦用户登录,路由就会检查身份验证以重定向到受保护的主路径。
我的第一直觉是从后端 (Django) 发送一个布尔值并使用它来创建一个守卫。但我一直看到在前端处理这个问题似乎是更好的做法。
我所做的是创建一个 auth.service.ts 和一个 auth.guard.ts。在该服务中,我尝试从浏览器中检索令牌,然后验证它是否已过期。然后我在守卫上调用该方法,return 是一个布尔值。问题是每次我在本地存储中查找令牌时,我都会返回 null。
有没有更好的方法来实现这个目标?
auth.guard.ts
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
Router,
RouterStateSnapshot,
UrlTree,
} from '@angular/router';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
):
| Observable<boolean | UrlTree>
| Promise<boolean | UrlTree>
| boolean
| UrlTree {
console.log(this.authService.isAuthenticated());
if(!this.authService.isAuthenticated()){
this.router.navigate(['/login']);
return false;
}
return true;
}
}
auth.service.ts
import { Injectable } from '@angular/core';
import { JwtHelperService } from '@auth0/angular-jwt';
@Injectable({
providedIn: 'root'
})
export class AuthService {
public jwtHelper: JwtHelperService = new JwtHelperService();
constructor() { }
isAuthenticated(){
const jwt = localStorage.getItem('token');
return !this.jwtHelper.isTokenExpired(jwt!);
}
}
app-routing.module.ts
...
import { AuthGuard } from './user/services/auth.guard'
const routes: Routes = [
{
path: '',
component: LandingComponent,
children: [
{ path: '', component: HomeComponent, canActivate: [AuthGuard],},
{ path: 'home', component: HomeComponent, canActivate: [AuthGuard],},
{
path: 'cohort-charts',
component: CohortChartsComponent,
children: [
{ path: 'selection', component: CohortSelectionComponent },
{ path: 'edit', component: CohortEditComponent },
{ path: '', redirectTo: 'selection', pathMatch: 'full' },
],
},
],
},
{
path: 'login',
component: LoginComponent,
},
{ path: '**', redirectTo: '' },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
我想每次你在本地存储中查找令牌时,你都会返回 null 因为你没有保存令牌,或者如果你这样做,你试图将令牌存储为 object,而不是序列化(作为字符串,对其进行字符串化),所以它不会存储,或者当你得到它时,你不会传递它.
无论如何,我想 管理整个 jwt/authentification 部分的最佳做法是使用拦截器:
而 Interceptor 是一项服务,它 拦截 您所有的 http 调用,您可以设置它自动执行某些操作(例如,编辑 jwt)。
有关如何添加和更新 headers 以及如何使用拦截器拦截请求和响应的更多信息:
https://angular.io/guide/http#adding-and-updating-headers
https://angular.io/guide/http#intercepting-requests-and-responses
我让你瞥见你是如何做的/你需要什么:
- 提供 Angular 拦截器
app.module.ts:
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: HttpJwtAuthInterceptor,
multi: true,
},
{ provide: BASE_PATH, useValue: environment.apiUrl },
],
- 首先,在您的 auth.service.ts 中,store/get 令牌 的 2 种方法
// STORE the token in localstore:
setToken(token:string){
// First, serialize it (but just if token is not string type).
const tokenString:string = JSON.stringify( token );
localStorage.setItem('token', tokenString);
}
// READ the token from localstorage and Deserialize
getToken(): string | null{
let token = localStorage.getItem( 'token' );
if( token !=null){
// You just need to parse if you serialized it inside setToken() method
token = JSON.parse(carItemsString);
}
return token;
}
- 然后,在你的拦截器中:
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
} from '@angular/common/http';
import { AuthService } from '../_services/auth.service';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const url="\yourAPI\endpoint";
// Get your token
cont myToken = this.authService.getToken();
// Add authorization header with token if available
if (myToken) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${myToken}`,
'Content-Type': 'application/json',
},
url,
});
}
…
return next.handle(request);
}