Angular Interceptor使用刷新令牌续订访问令牌

时间:2018-08-22 20:32:49

标签: angular interceptor angular-http-interceptors

我正在尝试在Angular 6中创建一个拦截器,以处理基于刷新令牌的新访问令牌的生成。问题是,这是基于Observables的,当我尝试发出POST请求以获取新的访问令牌时,observables的链已损坏。这是下面的组件代码:

import { HttpHandler, HttpInterceptor, HttpRequest, HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { UserService } from './user.service';
import { BehaviorSubject, Subscription } from '../../../../node_modules/rxjs';
import { CommonFunctions } from '../../common/components/common.component';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/delay';
import 'rxjs/add/observable/of';
import { of } from 'rxjs';
import { AccountService } from './account.service';
import { ConfigurationService } from './configuration.service';

@Injectable()
export class AuthInterceptorService implements HttpInterceptor {   

  isRefreshingToken: boolean;
  tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);
  currentToken: string;
  refreshToken: string;
  authTokenNew: string;
  getNewTokenSubscription: Subscription;

  constructor(private user: UserService, private common: CommonFunctions,
    private ws: AccountService, private config: ConfigurationService) {
    this.isRefreshingToken = false;
    this.currentToken = this.user.accessToken;
    this.refreshToken = this.user.refreshToken;
    this.authTokenNew = '';
    this.getNewTokenSubscription = null;
  }

  addToken(req: HttpRequest<any>, token: string): HttpRequest<any> {
    return req.clone({ setHeaders: { Authorization: 'Bearer ' + token } });
  }

  refreshTheToken(): Observable<string> {

    const payload = new URLSearchParams();
    payload.append('client_id', this.config.CLIENT_ID);
    payload.append('grant_type', this.config.REFRESH_TOKEN_GRANT_TYPE);
    payload.append('refresh_token', this.refreshToken);

    this.getNewTokenSubscription = this.ws.doLogIn(payload)
      .finally(() => {
        this.cleanupGetNewTokenSubscription();
      })
      .subscribe(
        (imResponse: HttpResponse<object>) => {
          this.authTokenNew = imResponse['access_token'];
          this.user.refreshToken = imResponse['refresh_token'];
        },
        (error: HttpErrorResponse) => {

        }
      );

      this.user.accessToken = this.authTokenNew;

      return of(this.authTokenNew).delay(200);
  }

  cleanupGetNewTokenSubscription() {
    if (this.getNewTokenSubscription) {
      this.getNewTokenSubscription.unsubscribe();
      this.getNewTokenSubscription = null;
    }
  }

  getMainAuthToken() {
    return this.user.accessToken;
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
    if (this.getMainAuthToken()) {
      return next.handle(this.addToken(req, this.getMainAuthToken()))
        .catch(error => {
          if (error instanceof HttpErrorResponse) {
            switch ((<HttpErrorResponse>error).status) {
              case 400:
                return this.handle400Error(error);
              case 401:
                return this.handle401Error(req, next);
            }
          } else {
            return Observable.throw(error);
          }
        });
    } else {
      return next.handle(req);
    }
  }

  handle401Error(req: HttpRequest<any>, next: HttpHandler) {
    if (!this.isRefreshingToken) {
      this.isRefreshingToken = true;

      this.tokenSubject.next(null);

      return this.refreshTheToken()
        .switchMap((newToken: string) => {
          if (newToken) {
            this.tokenSubject.next(newToken);
            return next.handle(this.addToken(req, newToken));
          }

          return this.logoutUser();
        })
        .catch(error => {
          return this.logoutUser();
        })
        .finally(() => {
          this.isRefreshingToken = false;
        });
    } else {
      return this.tokenSubject
        .filter(token => token != null)
        .take(1)
        .switchMap(token => {
          return next.handle(this.addToken(req, token));
        });
    }
  }

  handle400Error(error) {
    if (error && error.status === 400 && error.error && error.error.error === 'invalid_grant') {
      return this.logoutUser();
    }

    return Observable.throw(error);
  }

  logoutUser() {
    this.common.logOut();
    return Observable.throw('');
  }
}

问题出在refreshTheToken()方法中。在该调用完成之前,正在访问新令牌的值。有什么线索可以解决吗?

谢谢!

0 个答案:

没有答案