簡體   English   中英

Angular - JWT刷新令牌

[英]Angular - JWT Refresh Token

很長一段時間后,我沒有找到關於刷新令牌的方法TTL:30分鍾刷新TTL:2周

如果我在45分鍾后刷新頁面無效,那么我創建一個getAccessToken()函數來發送過期的令牌,然后再發回一個刷新的令牌。 最大的問題是,如果我的頁面發出超過1個ajax請求,那么如果第一個請求使我的令牌無效,則第二個請求強制我重新登錄,因為它發送空令牌

@NgModule({
providers: [
    {
        provide: AuthHttp,
        useFactory: authHttpServiceFactory,
        deps: [Http, RequestOptions, Router]
    }
]
})

export function authHttpServiceFactory(http: Http, options: RequestOptions, router: Router) {
return new AuthHttp(new AuthConfig({
    tokenName: 'token',
    tokenGetter: (() => getAccessToken(http,router)),
    //tokenGetter: (() => localStorage.getItem('JWToken')),
    globalHeaders: [{'Content-Type': 'application/json'}],
    noJwtError: true,
}), http, options);
}


function getAccessToken(http: Http, router:Router): Promise<string> {

let jwtHelper: JwtHelper = new JwtHelper();

let accessToken = localStorage.getItem('JWToken');

if( accessToken == '' || !accessToken || accessToken == undefined || accessToken == null){
    router.navigate(['./admin/login']);
    return;
}


if (jwtHelper.isTokenExpired(accessToken)) {
    return new Promise((resolve, reject) => {
        let refreshTokenService: RefreshTokenService = new RefreshTokenService(http);
        refreshTokenService.refreshToken(accessToken).subscribe((res: any) => {
            res = res.json();

            if(res.token) {
                localStorage.setItem('JWToken', res.token);
                resolve(res.token);

            }else{
                localStorage.removeItem('JWToken');

                router.navigate(['./admin/login']);
            }
        });
    });
} else {
    return Promise.resolve(accessToken);
}
}

我希望請求等待第一個請求的響應

  • 使用特殊服務在您的應用中發送所有http請求
  • 將401響應存儲在此服務內的緩沖區中,同時將一個observable存儲到您將返回給調用者。 第一個401發送令牌刷新請求
  • 當你有新的令牌時,用新令牌重復緩沖區中的所有請求,並使用新的響應調用它們的observable。

這是新的httpClient庫的注入器

import {Injectable, Injector} from "@angular/core";
import {HttpEvent, HttpHandler, HttpInterceptor, HttpResponse} from "@angular/common/http";
import {HttpRequest} from "@angular/common/http";
import {Observable} from "rxjs/Observable";
import {SiteService} from "../services/site.service";
import {Router} from "@angular/router";
import {LoadingService} from "../../components/loading/loading.service";
import {AuthenticationService} from "../services/authentication.service";

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

constructor(private router: Router,
            private siteService: SiteService,
            private loadingService: LoadingService,
            private injector: Injector) {
}



private fixUrl(url: string) {
    if (url.indexOf('http://') >= 0 || url.indexOf('https://') >= 0)
        return url;
    else
        return this.siteService.apiDomain() + url;
}

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

    let clonedRequest;
    if ( this.siteService.getJWToken() !== null ) {
        clonedRequest = req.clone({
            headers: req.headers.set('Authorization', 'Bearer ' + this.siteService.getJWToken()),
            url: this.fixUrl(req.url)
        });
    } else {
        clonedRequest = req.clone({
            url: this.fixUrl(req.url)
        });
    }

    let authenticationService = this.injector.get(AuthenticationService);

    this.loadingService.start();
    const started = Date.now();
    return next.handle(clonedRequest)
        .do(event => {
            if (event instanceof HttpResponse) {

                const elapsed = Date.now() - started;
                console.log('%c Request for ' + this.fixUrl(req.urlWithParams) + ' took ' + elapsed + ' ms.', 'background: #222; color: yellow');
            }
        })
        ._finally(() => {
            this.loadingService.stop();
        })
        .catch((res) => {
            if ((res.status === 401 || res.status === 403) && res.error.error === 'token_expired') {
                this.loadingService.start();
                return authenticationService.refreshToken().flatMap((data: any) => {
                    this.loadingService.stop();
                    if (data.token !== '') {
                        this.siteService.setCurrentUser(data.user);
                        this.siteService.setCurrentUserPermissions(data.permissions);
                        this.siteService.setJWToken(data.token);
                    } else {
                        this.siteService.removeCurrentUser();
                        this.siteService.removeCurrentUserPermissions();
                        this.siteService.removeJWToken();
                        this.router.navigate(['./auth/login']);
                        return Observable.throw(res);
                    }
                    let clonedRequestRepeat = req.clone({
                        headers: req.headers.set('Authorization', 'Bearer ' + this.siteService.getJWToken()),
                        url: this.fixUrl(req.url)
                    });
                    return next.handle(clonedRequestRepeat).do(event => {
                        if (event instanceof HttpResponse) {

                            const elapsed = Date.now() - started;
                            console.log('%c Request for ' + req.urlWithParams + ' took ' + elapsed + ' ms.', 'background: #222; color: yellow');
                        }
                    });
                })
            } else if (res.status === 400 && res.error.error === 'token_not_provided') {
                this.router.navigate(['./auth/login']);
                return Observable.throw(res);
            } else if (res.status === 401 && res.error.error === 'token_invalid') {
                this.router.navigate(['./auth/login']);
                return Observable.throw(res);
            } else {
                return Observable.throw(res);
            }

        });

}
}

並且不要忘記將緩存(瀏覽器)標頭發送到后端響應至少幾秒鍾。

function getAccessToken(http: Http, router: Router, refreshTokenService: RefreshTokenService): Promise<string> {

let jwtHelper: JwtHelper = new JwtHelper();

let accessToken = localStorage.getItem('JWToken');

if (accessToken == '' || !accessToken || accessToken == undefined || accessToken == null) {
    router.navigate(['./admin/login']);
    return;
}

if (jwtHelper.isTokenExpired(accessToken)) {

    let waitPeriod = (!refreshTokenService.wait);

    refreshTokenService.wait = true;

    return new Promise((resolve, reject) => {

        if (waitPeriod) {
            refreshTokenService.refreshToken(accessToken).subscribe((res: any) => {
                res = res.json();

                if (res.token) {
                    localStorage.setItem('JWToken', res.token);
                    resolve(res.token);
                    refreshTokenService.wait = false;
                } else {
                    localStorage.removeItem('JWToken');
                    router.navigate(['./admin/login']);
                }

            });
        } else {
            let interval = setInterval(function () {
                if(refreshTokenService.wait == false) {
                    resolve(localStorage.getItem('JWToken'));
                    clearInterval(interval);
                }
            }, 500);
        }

    });
} else {
    return Promise.resolve(accessToken);
}
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM