Angular - 如何使用Authentication Interceptor刷新JWT令牌

时间:2018-04-22 10:09:29

标签: angular angular-http

当用户登录时,他们会获得token_a。要在应用程序中发出任何API请求,他们需要token_b。 token_b是使用token_a生成的。

我已经构建了一个身份验证拦截器,它在用户登录后将token_b附加到所有后续api调用的头部。但是,token_b上有一个很短的到期时间,因此必须重新生成token_b。

auth.interceptor.ts

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpRequest, HttpEvent, HttpResponse, HttpClient, HttpBackend } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';

import { AuthService } from './../services/auth/auth.service';
import { JwtService } from './../services/jwt/jwt.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    private httpClient: HttpClient;

    constructor(private auth: AuthService, private jwt: JwtService, private http: HttpBackend) {
        this.httpClient = new HttpClient(http);
    }

    setHeader(req) {

        const authToken = this.auth.getProfileToken();

        const authReq = req.clone({
            headers: req.headers.set('Authorization', 'Bearer ' + authToken)
        });

        return authReq;
    }

    intercept(req: HttpRequest<any>, next: HttpHandler) {

        const InterceptorSkipHeader = 'X-Skip-Interceptor';

        if (req.headers.has(InterceptorSkipHeader)) {
            const headers = req.headers.delete(InterceptorSkipHeader);
            return next.handle(req.clone({ headers }));
        }

        if (this.auth.hasProfileToken() && this.auth.isProfileTokenExpired()) {

            const result = this.refreshToken();
            const ar = this.setHeader(req);
            return next.handle(ar);
        }

        const authReq = this.setHeader(req);
        return next.handle(authReq);

    }


    async refreshToken() {

        const token = localStorage.getItem('token');

        return await this.httpClient.post('//api/v1/users/login', { 'token': token })
            .subscribe((res: any) => {
                localStorage.setItem('profile_token', res.token);
                return res;
            });

    }

}

在拦截器函数中,我检查profileToken(token_b)是否存在以及它是否已过期。如果是我试图调用设置新令牌的refreshToken。

然而,在拦截器传递请求之前,我发现refreshToken没有完成。

1 个答案:

答案 0 :(得分:0)

由于refreshToken()是异步函数,因此您需要在传递请求之前等待它完成。一种方法是将refreshToken()链接/管道传输到next.handle(ar)

intercept(req: HttpRequest<any>, next: HttpHandler) {

    const InterceptorSkipHeader = 'X-Skip-Interceptor';

    if (req.headers.has(InterceptorSkipHeader)) {
        const headers = req.headers.delete(InterceptorSkipHeader);
        return next.handle(req.clone({ headers }));
    }

    if (this.auth.hasProfileToken() && this.auth.isProfileTokenExpired()) {

        return this.refreshToken().switchMap(() => {
            const ar = this.setHeader(req);
            return next.handle(ar);
        });
    }

    const authReq = this.setHeader(req);
    return next.handle(authReq);

}


refreshToken() {

    const token = localStorage.getItem('token');

    return this.httpClient.post('//api/v1/users/login', { 'token': token })
        .map((res: any) => {
            localStorage.setItem('profile_token', res.token);
            return res;
        });

}