我如何保护 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

我让你瞥见你是如何做的/你需要什么:

  1. 提供 Angular 拦截器
app.module.ts:
 providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: HttpJwtAuthInterceptor,
      multi: true,
    },
    { provide: BASE_PATH, useValue: environment.apiUrl },
  ],
  1. 首先,在您的 auth.service.ts 中,store/get 令牌
  2. 的 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;
 
}
  1. 然后,在你的拦截器中:
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);

    }