当前位置: 首页 > 知识库问答 >
问题:

Angular 4.3-HTTP拦截器-刷新JWT令牌

夏飞鹏
2023-03-14

我需要(在拦截器类中)对403禁止的HTTP状态(获取/刷新)JWT令牌作出反应,并使用新令牌重试请求。

在下面的代码中,当服务器返回错误响应时,它将转到成功回调(而不是像我预期的那样进入错误回调),事件是typeof object(这在错误响应的反应中是无用的)。事件对象如下所示:{type:0}。

问题:

-当我需要刷新accessToken并重试http请求时,如何在HttpInterceptor中正确处理httpErrorResponse(403禁止)?

 import {
  HttpInterceptor,
  HttpRequest,
  HttpResponse,
  HttpHandler,
  HttpEvent
} from '@angular/common/http';
import 'rxjs/add/operator/map';

@Injectable()
class JWTInterceptor implements HttpInterceptor {

  constructor(private tokenService: TokenService) {}
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  let myHeaders = req.headers;
  if (this.tokenService.accessToken) {
        myHeaders = myHeaders.append('Authorization',`${this.tokenService.accessToken.token_type} ${this.tokenService.accessToken.access_token}`)
   }

  const authReq = req.clone({headers: myHeaders});

    return next.handle(authReq).map((event: HttpEvent<any>) => {
      if (event instanceof HttpResponse) {
        // success callback
      }
    }, (err: any) => {
      if (err instanceof HttpErrorResponse {
        if (err.status === 403) {
          // error callback
          this.tokenService.obtainAccessToken()
        }
      }
    })
      .retry(1);
  }
}

共有3个答案

容宏逸
2023-03-14

我只是想和大家分享一下对我有用的东西:

@Injectable()
export class AutoReLoginInterceptor implements HttpInterceptor {

    constructor() {
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // as we want to intercept the possible errors, instead of directly returning the request execution, we return an Observable to control EVERYTHING
        return new Observable<HttpEvent<any>>(subscriber => {

            // first try for the request
            next.handle(req)
                .subscribe((event: HttpEvent<any>) => {
                        if (event instanceof HttpResponse) {
                            // the request went well and we have valid response
                            // give response to user and complete the subscription
                            subscriber.next(event);
                            subscriber.complete();
                        }
                    },
                    error => {
                        if (error instanceof HttpErrorResponse && error.status === 401) {
                            console.log('401 error, trying to re-login');

                            // try to re-log the user
                            this.reLogin().subscribe(authToken => {
                                // re-login successful -> create new headers with the new auth token
                                let newRequest = req.clone({
                                    headers: req.headers.set('Authorization', authToken)
                                });

                                // retry the request with the new token
                                next.handle(newRequest)
                                    .subscribe(newEvent => {
                                        if (newEvent instanceof HttpResponse) {
                                            // the second try went well and we have valid response
                                            // give response to user and complete the subscription
                                            subscriber.next(newEvent);
                                            subscriber.complete();
                                        }
                                    }, error => {
                                        // second try went wrong -> throw error to subscriber
                                        subscriber.error(error);
                                    });
                            });
                        } else {
                            // the error was not related to auth token -> throw error to subscriber
                            subscriber.error(error);
                        }
                    });
        });

    }

    /**
     * Try to re-login the user.
     */
    private reLogin(): Observable<string> {
        // obtain new authorization token and return it
    }
}
戚侯林
2023-03-14

您需要从RxJS添加catch操作符。这就是错误所在,您可以相应地处理它。

当出现状态为0的错误时,很可能意味着远程服务器已关闭,无法建立连接。

看看我的示例逻辑:

this.http.request(url, options)
        .map((res: Response) => res.json())
        .catch((error: any) => {
            const err = error.json();

            // Refresh JWT
            if (err.status === 403) {
                // Add your token refresh logic here.
            }

            return Observable.throw(err);
        });

为了让您的刷新逻辑通过拦截器,您需要返回调用,函数还应该返回一个可观察的。例如修改上面的原始逻辑:

this.http.request(url, options)
        .map((res: Response) => res.json())
        .catch((error: any) => {
            const err = error.json();

            // Refresh JWT
            if (err.status === 403) {
                // refreshToken makes another HTTP call and returns an Observable.
                return this.refreshToken(...);
            }

            return Observable.throw(err);
        });

如果您希望能够重试原始请求,您可以做的是传递原始请求数据,以便在成功刷新令牌后可以再次进行调用。例如,这就是refreshtToken函数的外观:

refreshToken(url: stirng, options: RequestOptionsArgs, body: any, tokenData: any): Observable<any>
    return this.post(`${this.url}/token/refresh`, tokenData)
        .flatMap((res: any) => {
            // This is where I retry the original request
            return this.request(url, options, body);
        });
}
景康安
2023-03-14

我对这个问题的最终解决方案:

@Injectable()
export class WebApiInterceptor implements HttpInterceptor {
  constructor(private tokenService: TokenService) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log('*An intercepted httpRequest*', req, this.tokenService.accessToken);
    const authReq = this.authenticateRequest(req);
    console.log('*Updated httpRequest*', authReq);
    return next.handle(authReq)
      .map((event: HttpEvent<any>) => {
        if (event instanceof HttpResponse) {
          console.log('*An intercepted httpResponse*', event);
          return event;
        }
      })
      .catch((error: any) => {
        if (error instanceof HttpErrorResponse) {
          if (error.status === 403 && error.url !== environment.authEndpoint) {
            return this.tokenService
              .obtainAccessToken()
              .flatMap((token) => {
                const authReqRepeat = this.authenticateRequest(req);
                console.log('*Repeating httpRequest*', authReqRepeat);
                return next.handle(authReqRepeat);
              });
          }
        } else {
          return Observable.throw(error);
        }
      })
  }
}

功能

authenticateRequest(req)

只需将授权头添加到原始请求的副本中

功能

obtainAccessToken()

获取新的令牌表单授权服务器并将其存储

 类似资料:
  • 我有 401 拦截器,当access_token过期时,有一个请求的成功案例。拦截器重新加载令牌并返回 next.handle(customReq)。但是当同时发出 2 个或更多请求并且两个请求的令牌都已过期时,我遇到了问题,因为第二个请求尝试再次刷新,但现在刷新令牌无效。所以。。。。我尝试设置一个标志只执行一次,并使用自定义可观察量返回。问题是组件现在永远不会成功,我无法删除加载器。 HTTP

  • 问题内容: 我有一个有角度的应用程序,有时每个状态会执行多个$ http.get请求。该应用将JWT用于带有刷新令牌的用户身份验证。API服务器会发送由于身份验证错误而失败的每个请求。我做了一个请求,该请求在401错误时请求带有刷新令牌的新令牌,然后重新发送原始请求。 问题是,如果一个状态发出例如2个$ http.get请求,并且都获得401响应,那么我将访问令牌更新两次。显然,我只想刷新一次令牌

  • 我已经实现了 JWT 和刷新令牌流。当我过去实现这一点时,我的做法略有不同,主要是刷新令牌是在正文中发送的。 但是现在我做了不同的事情,我必须通过授权标头发送访问令牌,但是我的拦截器代码不想切换不记名令牌。如何修复,如果我想刷新,我实际上使用刷新令牌作为不记名令牌,而不是过期的访问令牌? 我还尝试在post请求中将HTTP标头设置为授权承载令牌

  • 我有一个使用express api的react应用程序。我正在尝试在访问令牌过期时刷新令牌。我正在使用axios拦截器来实现这一成就。 它卡在某个地方了。我使用console.log来调试它。从控制台; 发布http://localhost:5000/api/auth/token?null 401(未经授权) 之后什么都没发生。我该怎么办?谢谢你的帮助

  • 我正在从事一个spring boot angular项目,其中用户从angular前端登录到spring boot上的身份验证api,该api返回一个JWT令牌。我还在Angular上设置了一个拦截器,该拦截器为所有请求附加带有JWT令牌的授权头。 我正在寻找一种拦截angualar请求的方法,这样当spring boot在JWT令牌过期后抛出401错误时,Angular前端将尝试使用过期的JWT

  • 我正在构建一个移动应用程序,并且正在使用JWT进行身份验证。 最好的方法似乎是将JWT访问令牌与刷新令牌配对,这样我就可以根据需要频繁地使访问令牌过期。 刷新令牌是什么样子的?是随机字符串吗?那串加密了吗?是另一个JWT吗? 刷新令牌将存储在用户模型的数据库中以便访问,对吗?在这种情况下似乎应该加密 在用户登录后,我是否会将刷新令牌发送回,然后让客户端访问单独的路由来检索访问令牌?