【问题标题】:How to refresh JWT Tokens using Angular Http Interceptor and RxJS?如何使用 Angular Http Interceptor 和 RxJS 刷新 JWT 令牌?
【发布时间】:2019-03-17 02:08:00
【问题描述】:

我正在使用两个 JWT 令牌 - Refresh Token(7 天后过期)和 Access Token(15 分钟后过期)。它们存储在httpOnly cookies 上,可以通过服务器访问。 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 needs to be checked first
            if (Number(expirationTokenRefresh) < Date.now()) {
                // new refresh token is stored on cookie
                this.authService.refreshTokenRefresh();
                // this.authService.refreshToken().subscribe(() => { ... });
            }
            // next we check Access Token
            if (Number(expirationToken) < Date.now()) {
              // new access token is stored on cookie
              this.authService.refreshToken();
         // this.authService.refreshTokenRefresh().subscribe(() => { ... });
            }
            return next.handle(req.clone({
                withCredentials: true
            }));
    }

}

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

这里是Express 后端方法:

//routes
const express = require('express');
const router = express.Router();
router.get('/refreshtoken', user.refreshToken);
router.get('/refreshtokenref', user.refreshTokenRefresh);

// refresh access token method
const jwt = require('jsonwebtoken');
const moment = require('moment');
const User = require('../models/user');
exports.refreshToken = wrap(async(req, res, next) => {
    const user = await User.findOne({ refresh_token: req.cookies['tokenref'] });
    if (user) {
        const newToken = await jwt.sign(
            { email: user.email, userId: user._id, role: user.role },
            process.env.JWT_Key,
            { expiresIn: '15m' });
        const expiresAt = moment().add(900, 'second');
        res.cookie('tokenexp', JSON.stringify(expiresAt.valueOf()), { maxAge: 3000000000, secure: true});
        res.cookie('token', newToken, { maxAge: 3000000000, secure: true, httpOnly: true });
        res.status(200).json({success: true});
    } else {
        res.status(401).json({success: false, message: 'Sessão expirou.'});
    }
});

如何使用RxJS Observables 使其工作?我可能会发送一个请求来刷新令牌,然后发送另一个请求来刷新第二个令牌,最后是带有更新 cookie 的原始请求。总之,我可能需要在我的原始请求之前发送请求。 还有一个问题:AuthInterceptor 不应该在请求一两个(令牌)之后调用。

【问题讨论】:

    标签: javascript node.js angular express rxjs


    【解决方案1】:

    使用mergeMap依次检查token的有效性。

    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 })))
    )
    

    【讨论】:

    • mergeMap之间导航时如何避免多次HttpInterceptor调用?我正在尝试使用HttpBackend 发送请求,例如const http = new HttpClient(this.handler); return this.http.get(${BACKEND_URL}/refreshtoken);,但效果不佳
    • 好问题。对于这种情况,这不是一个非常简单的设置。您能否为此提出一个新问题,我会尽力回答。
    • ok 提出了另一个问题。你去:link
    猜你喜欢
    • 2021-04-06
    • 2017-10-11
    • 2016-10-14
    • 1970-01-01
    • 2017-12-31
    • 2018-06-12
    • 2014-12-22
    • 2020-01-25
    • 1970-01-01
    相关资源
    最近更新 更多