Angular 7-如何共享可观察的令牌续约? [英] Angular 7 - How can I share the token renewal Observable?

查看:87
本文介绍了Angular 7-如何共享可观察的令牌续约?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在每个请求之前,HTTP拦截器都会检查访问令牌是否过期,如果已过期,则它首先更新令牌,然后继续请求.

Before each request a HTTP interceptor checks if the access token is expired and if so, it first renews the token and then continues the request.

问题出在具有多个请求的页面上.在这些页面上,拦截器会尝试为每个请求续订令牌.

The problem is on pages that have multiple requests. On those pages the interceptor tries to renew the token for each request.

在这种情况下如何共享令牌续期请求?

How can I share the token renewal request in this case?

负责令牌更新的方法是:

The method that is responsible for token renewal is this:

renewToken() {

    let refreshToken = // get refresh token

    let accessToken = // get access token

    if (!refreshToken || !accessToken)
      return;

    let requestData = {
      accessToken: accessToken,
      refreshToken: refreshToken
    }

    return this.http.post<ApplicationToken>(`${this.baseUrl}/renewToken`, requestData)
      .pipe(
        // I tried share() shareReplay(1) and publishReplay(1) here but no luck
      );
}

这是拦截器使用该方法的方式:

And this is how the interceptor uses that method:

...
// in case we need to renew the token
return this.accountService.renewToken()
  .pipe(                        
    switchMap(t => {

      this.accountService.saveToken(t);
      token = this.accountService.getAccessToken();

      var newReq = this.setToken(req, token);
      return next.handle(newReq);
    })
  );
...

推荐答案

您需要检查刷新令牌请求是否正在进行,因为您不希望其他呼叫进入并再次调用refreshToken.

You need to check if refresh token request is in progress or not because you don’t want other calls to come in and call refreshToken again.

在这里,我为您创建了RefreshTokenInterceptor类.

Here I've created RefreshTokenInterceptor class for you.

您只需要对其进行自定义并遵循注释:

You just need to customize it and follow the comments:

import { Injectable } from "@angular/core";
import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler } from "@angular/common/http";
import { BehaviorSubject, Observable } from "rxjs";
import { catchError, switchMap, filter, take } from "rxjs/operators";

@Injectable({
    providedIn: 'root'
})
export class RefreshTokenInterceptor implements HttpInterceptor {

    private refreshTokenInProgress: boolean = false;

    private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(
        null
    );

    constructor(public accountService: AccountService) {}

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

        // Check first if token has expired
        // If not, just add addAuthenticationToken();

        // If expired
        if (tokenHasExpired()) {

            if (this.refreshTokenInProgress) {

                // If refreshTokenInProgress is true, we will wait until refreshTokenSubject has a non-null value
                // – which means the new token is ready and we can retry the request again
                return this.refreshTokenSubject.pipe(
                    filter(result => result !== null),
                    take(1),
                    switchMap(() => next.handle(this.addAuthenticationToken(request)))
                );

            } else {

                this.refreshTokenInProgress = true;

                // Set the refreshTokenSubject to null so that subsequent API calls will wait until the new token has been retrieved
                this.refreshTokenSubject.next(null);

                return this.accountService.renewToken()
                        .pipe(                        
                            switchMap(t => {

                                this.accountService.saveToken(t);
                                let token = this.accountService.getAccessToken();

                                this.refreshTokenInProgress = false; // Set refreshTokenInProgress to False
                                this.refreshTokenSubject.next(token); // Add token to the refreshTokenSubject

                                var newReq = this.setToken(req, token);
                                return next.handle(newReq);

                            }),
                            catchError((err) => {

                                this.refreshTokenInProgress = false;
                                return Observable.throw(err);

                            })
                        );
            }

        } else {

            return this.addAuthenticationToken(request);

        }

    }

    addAuthenticationToken(request) {
        // Get access token from Local Storage
        const accessToken = this.accountService.getAccessToken();

        // If access token is null this means that user is not logged in
        // And we return the original request
        if (!accessToken) {
            return request;
        }

        // We clone the request, because the original request is immutable
        return request.clone({
            setHeaders: {
                Authorization: accessToken
            }
        });
    }

}

这篇关于Angular 7-如何共享可观察的令牌续约?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆