Angular 8拦截调用以刷新令牌 [英] Angular 8 Intercept call to refresh token

查看:79
本文介绍了Angular 8拦截调用以刷新令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果当前访问令牌已过期,我正在尝试刷新访问令牌.

I am trying to refresh access token if current access token is expired.

我一次发送多个请求,并且希望创建一个队列,因此其他请求将不会请求刷新令牌路由.

I am sending multiple requests at one time and I want to make a kind of a queue, so other requests won't request refreshing token route.

我已经搜索了一些最佳实践和示例,并找到了针对Angular 6和rxjs v6的以下解决方案,它们使用了BehaviourSubject和switchMaps.(请参阅附件代码)

I've googled some best practises and examples and found out the following solution for Angular 6 and rxjs v6, which is using BehaviourSubject and switchMaps. (please see attached code)

但是我使用的是Angular 8(8.1)和rxjs v6.4,此解决方案不适用于我.

However I am using Angular 8 (8.1) and rxjs v6.4 and this solution does not work for me.

它根本无法到达 this.authService.requestAccessToken().pipe 中的 switchMap .(使用console.log测试)

It simply does not reach switchMap in this.authService.requestAccessToken().pipe. (Tested using console.log)

但是,如果我发表评论返回this.refreshTokenSubject.pipe 并返回 next.handle(request),它将到达该switchMap,但其他请求失败.

However if I comment return this.refreshTokenSubject.pipe and return next.handle(request) it reaches that switchMap, but my other requests are failed.

您知道是否已更改任何内容,还是应该尝试以其他方式进行此操作?

Do you know if anything has been changed or should I try doing this in another way?

  • 令牌拦截器
    import { Injectable } from '@angular/core';
    import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
    import { AuthService } from './auth.service';
    import { Observable, BehaviorSubject, Subject } from 'rxjs';
    import { switchMap, take, filter } from 'rxjs/operators';
    @Injectable()
    export class TokenInterceptor implements HttpInterceptor {
        private refreshTokenInProgress = false;
        private refreshTokenSubject: Subject<any> = new BehaviorSubject<any>(null);

        constructor(public authService: AuthService) { }
        intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

            const accessExpired = this.authService.isAccessTokenExpired();
            const refreshExpired = this.authService.isRefreshTokenExpired();

            if (accessExpired && refreshExpired) {
                return next.handle(request);
            }
            if (accessExpired && !refreshExpired) {
                if (!this.refreshTokenInProgress) {
                    this.refreshTokenInProgress = true;
                    this.refreshTokenSubject.next(null);
                    return this.authService.requestAccessToken().pipe(
                        switchMap((authResponse) => {
                            this.authService.saveToken(AuthService.TOKEN_NAME, authResponse.accessToken);
                            this.authService.saveToken(AuthService.REFRESH_TOKEN_NAME, authResponse.refreshToken);
                            this.refreshTokenInProgress = false;
                            this.refreshTokenSubject.next(authResponse.refreshToken);
                            return next.handle(this.injectToken(request));
                        }),
                    );
                } else {
                    return this.refreshTokenSubject.pipe(
                        filter(result => result !== null),
                        take(1),
                        switchMap((res) => {
                            return next.handle(this.injectToken(request))
                        })
                    );
                }
            }

            if (!accessExpired) {
                return next.handle(this.injectToken(request));
            }
        }

        injectToken(request: HttpRequest<any>) {
            const token = this.authService.getToken(AuthService.TOKEN_NAME);
            return request.clone({
                setHeaders: {
                    Authorization: `Bearer ${token}`
                }
            });
        }
    }

  • requestAccessToken
  •     requestAccessToken(): Observable<any> {
            const refreshToken = this.getToken(AuthService.REFRESH_TOKEN_NAME);
            return this.http.post(`${this.basePath}/auth/refresh`, { refreshToken });
        }
    


    UPD 1

    所以我用这些资料来编写我的拦截器:


    UPD 1

    So I used these sources to write my interceptor:

    • https://itnext.io/angular-tutorial-implement-refresh-token-with-httpinterceptor-bfa27b966f57 (Angular 4 solution, I believe it edpends on rxjs version)

    https://github.com/melcor76/interceptors/blob/master/src/app/interceptors/auth.interceptor.ts

    我已经从拦截器范围中排除了 refresh 请求,现在它可以正常工作了感谢@JBNizet

    I've excluded refresh request from interceptor scope and now it's working Thanks to @JBNizet

    推荐答案

    我已经从拦截器范围中排除了刷新请求,现在它可以正常工作了.我已进行临时修复,以查看其以最快的方式运行.

    I've excluded refresh request from interceptor scope and now it's working. I've made a temporary fix in order to see it's working in the fastest way.

    现在我的TokenInterceptor看起来像:

    Now my TokenInterceptor looks like:

    import { Injectable } from '@angular/core';
    import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
    import { AuthService } from './auth.service';
    import { Observable, BehaviorSubject, Subject } from 'rxjs';
    import { switchMap, take, filter } from 'rxjs/operators';
    @Injectable()
    export class TokenInterceptor implements HttpInterceptor {
        private refreshTokenInProgress = false;
        private refreshTokenSubject: Subject<any> = new BehaviorSubject<any>(null);
    
        constructor(public authService: AuthService) { }
        intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
            if (request.url.indexOf('refresh') !== -1) {
                return next.handle(request);
            }
    
            const accessExpired = this.authService.isAccessTokenExpired();
            const refreshExpired = this.authService.isRefreshTokenExpired();
    
            if (accessExpired && refreshExpired) {
                return next.handle(request);
            }
            if (accessExpired && !refreshExpired) {
                if (!this.refreshTokenInProgress) {
                    this.refreshTokenInProgress = true;
                    this.refreshTokenSubject.next(null);
                    return this.authService.requestAccessToken().pipe(
                        switchMap((authResponse) => {
                            this.authService.saveToken(AuthService.TOKEN_NAME, authResponse.accessToken);
                            this.authService.saveToken(AuthService.REFRESH_TOKEN_NAME, authResponse.refreshToken);
                            this.refreshTokenInProgress = false;
                            this.refreshTokenSubject.next(authResponse.refreshToken);
                            return next.handle(this.injectToken(request));
                        }),
                    );
                } else {
                    return this.refreshTokenSubject.pipe(
                        filter(result => result !== null),
                        take(1),
                        switchMap((res) => {
                            return next.handle(this.injectToken(request))
                        })
                    );
                }
            }
    
            if (!accessExpired) {
                return next.handle(this.injectToken(request));
            }
        }
    
        injectToken(request: HttpRequest<any>) {
            const token = this.authService.getToken(AuthService.TOKEN_NAME);
            return request.clone({
                setHeaders: {
                    Authorization: `Bearer ${token}`
                }
            });
        }
    }
    

    感谢@JBNizet

    Thanks to @JBNizet

    这篇关于Angular 8拦截调用以刷新令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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