使用Angular 6拦截器刷新令牌

时间:2019-06-13 02:00:46

标签: angular access-token angular-http-interceptors

我正在尝试在我的angular 6应用程序中实现刷新令牌功能。对此有很多教程,我正在遵循http://ericsmasal.com/2018/07/02/angular-6-with-jwt-and-refresh-tokens-and-a-little-rxjs-6/https://www.intertech.com/Blog/angular-4-tutorial-handling-refresh-token-with-new-httpinterceptor/教程来实现。两者基本上有相同的想法。 但是我觉得我面临的问题是由于我们当前的调用刷新令牌功能的结构。以下是说明

1) AuthInterceptor

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

 constructor(private authService: AuthenticationService) { }

 isRefreshingToken: boolean = false;
 tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);

intercept(request: HttpRequest<any>, next: HttpHandler) : Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any> | any> {

return next.handle(this.addTokenToRequest(request, this.authService.getAuthToken()))
  .pipe(
    catchError(err => {
      if (err instanceof HttpErrorResponse) {
        switch ((<HttpErrorResponse>err).status) {
          case 401:
            return this.handle401Error(request, next);
          case 400:
            return <any>this.authService.logout();
        }
      } else {
        return throwError(err);
      }
    }));
}

 private addTokenToRequest(request: HttpRequest<any>, token: string) : HttpRequest<any> {
return request.clone({ setHeaders: { Authorization: `Bearer ${token}`}});
}

private handle401Error(request: HttpRequest<any>, next: HttpHandler) {

if(!this.isRefreshingToken) {
  this.isRefreshingToken = true;

  // Reset here so that the following requests wait until the token
  // comes back from the refreshToken call.
  this.tokenSubject.next(null);

  return this.authService.refreshToken()
    .pipe(
      switchMap((user) => {
        if(user) {
          this.tokenSubject.next(user.accessToken);;
          localStorage.setItem('currentUser', JSON.stringify(user));
          return next.handle(this.addTokenToRequest(request, user.accessToken));
        }

        return <any>this.authService.logout();
      }),
      catchError(err => {
        return <any>this.authService.logout();
      }),
      finalize(() => {
        this.isRefreshingToken = false;
      })
    );
} else {
  this.isRefreshingToken = false;

  return this.tokenSubject
    .pipe(filter(token => token != null),
      take(1),
      switchMap(token => {
      return next.handle(this.addTokenToRequest(request, token));
    }));
  }
 }
}

2) AuthService

我们的刷新令牌服务通过以下规则调用

  1. 要调用刷新令牌,我们发送带有Basic标头和值btoa(someid + someotherid)的请求
  2. 在该请求的正文中,我们传递了刷新令牌,这是我们从初始登录处收到的

      refreshToken() : Observable<any> {
      let currentUser = JSON.parse(localStorage.getItem('currentUser'));
      let token = currentUser.refreshToken;
      let headers = new HttpHeaders();
      headers.append('Authorization', 'Basic '+btoa(someid+someotherid));
      let body = new URLSearchParams();
      body.append('grant_type', 'refresh_token);
      body.append('refresh_token', token); <--As commented in no.2
      return this.http.post("http://localhost:53217/api/Account/Token/Refresh", body.toString())
      .pipe(
            map(user => {
    
      if (user && user.accessToken) {
        localStorage.setItem('currentUser', JSON.stringify(user));
      }
    
      return user;
       }));
      }
    
      getAuthToken() : string {
      let currentUser = JSON.parse(localStorage.getItem('currentUser'));
    
       if(currentUser != null) {
      return currentUser.accessToken;
      }
    
      return '';
      }
    

观察

  1. 它在auth服务中调用refreshtoken方法,但随后再次从authinterceptor传递到else块并调用addTokenToRequest()。因此,与其将标头添加为基本标头,不如附加承载符并再次发送回401错误。

以上代码使用本地存储,我们使用cookie。 EG-this.cookieService.get('access_token'),this.cookieService.set('refresh_token','ddsdhsdhsdhsdhs')

简而言之,我的refreshtoken方法应首先使用Basic调用API,然后在收到令牌时调用带有附加新令牌的Bearer的其他API。

请帮助我,因为我被困了几天。 谢谢

1 个答案:

答案 0 :(得分:1)

有同样的问题,所以我需要检查拦截器中的标头。

  // exempt some paths from authentication
      if (req.headers.get('authExempt') === 'true') {
        return next.handle(req);
      }

这都是假设您致电服务一样

 getInfo():Observable<any>{
    return this.http.get<any>(API_URL + 'getDocs', httpOptions);
  }

和您的httpOptions看起来像

const httpOptions = {
  headers: new HttpHeaders({
   'authExempt': 'true',
 'Content-Type': 'application/json'})
};