【问题标题】:How to avoid multiple HttpInterceptor calls while navigating between RxJS mergeMap?在 RxJS mergeMap 之间导航时如何避免多个 HttpInterceptor 调用?
【发布时间】:2019-03-17 18:44:07
【问题描述】:

我正在使用两个 JWT 令牌 - 刷新令牌(7 天后过期)和访问令牌(15 分钟后过期)。它们存储在 httpOnly cookie 中,可以通过服务器访问。 Refresh 方法对新令牌进行签名并将其存储在 cookie 中。我需要在每次这样的请求后检查这些令牌是否过期:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    constructor(private authService: AuthService, private cookieService: CookieService) { }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
            const expirationToken = this.cookieService.get('tokenexp'); // access token expiration
            const expirationTokenRefresh = this.cookieService.get('tokenrefexp'); // refresh expiration
            
            // refresh token -> access token -> original request
            return of(Number(expirationTokenRefresh) < Date.now()).pipe(
              mergeMap(expire => expire
                ? this.authService.refreshTokenRefresh()
                : of(Number(expirationToken) < Date.now())
              ),
              mergeMap(expire => expire
                ? this.authService.refreshToken()
                : of(true)
              ),
              mergeMap(ok => next.handle(req.clone({ withCredentials: true })))
            );
    }

}

// auth service
refreshToken() {
  return this.http.get(`${BACKEND_URL}/refreshtoken`);
}
refreshTokenRefresh() {
  return this.http.get(`${BACKEND_URL}/refreshtokenref`);
}

我可能会发送一个刷新令牌的请求,然后发送另一个刷新第二个令牌的请求,最后是带有更新 cookie 的原始请求。总之,我可能需要在原始请求之前发送请求。

问题是:每次发出请求时,都会有一个请求循环到AuthInterceptor。请求一和二(令牌)不应调用AuthInterceptor

【问题讨论】:

  • 说实话,我不喜欢Interceptor,因为它更难控制,更难预测。通常我创建自己的ApiService 并环绕HttpClient 来操作通用http 调用。这可能不是你的解决方案,所以我只是把这里作为评论而不是 anwser。
  • 你能提供一些顺序请求的例子吗?
  • 您可以在此处设置一个条件以跳过拦截这两个调用。

标签: javascript node.js angular express rxjs


【解决方案1】:

如果请求 url 是用于令牌,则进行条件检查以跳过拦截器。

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    constructor(private authService: AuthService, private cookieService: CookieService) { }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    
            if(req.url===`${BACKEND_URL}/refreshtoken` || req.url ===`${BACKEND_URL}/refreshtokenref`)
              return next.handle(req.clone({ withCredentials: true }))
            
            const expirationToken = this.cookieService.get('tokenexp'); // access token expiration
            const expirationTokenRefresh = this.cookieService.get('tokenrefexp'); // refresh expiration
            
            // refresh token -> access token -> original request
            return of(Number(expirationTokenRefresh) < Date.now()).pipe(
              mergeMap(expire => expire
                ? this.authService.refreshTokenRefresh()
                : of(Number(expirationToken) < Date.now())
              ),
              mergeMap(expire => expire
                ? this.authService.refreshToken()
                : of(true)
              ),
              mergeMap(ok => next.handle(req.clone({ withCredentials: true })))
            );
    }

}

// auth service
refreshToken() {
  return this.http.get(`${BACKEND_URL}/refreshtoken`);
}
refreshTokenRefresh() {
  return this.http.get(`${BACKEND_URL}/refreshtokenref`);
}

请同意@Xinan 的观点,即拦截器有时会成为更大的问题。创建自己的http服务可能会更好

class HttpService{
   constructoer(private _http:HttpClient)

   preIntercept(url,options){
     this._http.get(tokenUrl).pipe(
       map(res=>{
           //do your stuff
            return {url,options}
        }))

}

get(url,options={}){
    return this.preIntercept(url,options).pipe(
    mergeMap(({url,options})=>this._http.get(url,options))
}

}

【讨论】:

  • 我想我快完成了...只需要在发送最后一个mergeMap 之前更改req.cookies['token']req.cookies['tokenexp']。我正在设置 res.cookie('tokenexp', expiration);res.cookie('token', newToken) 但它不会改变原来的 req 对象
猜你喜欢
  • 1970-01-01
  • 2019-03-21
  • 2022-01-24
  • 1970-01-01
  • 2018-04-07
  • 1970-01-01
  • 2020-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多