如何使用 Angular Http Interceptor 和 RxJS 刷新 JWT 令牌?
Posted
技术标签:
【中文标题】如何使用 Angular Http Interceptor 和 RxJS 刷新 JWT 令牌?【英文标题】:How to refresh JWT Tokens using Angular Http Interceptor and RxJS? 【发布时间】: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
不应该在请求一两个(令牌)之后调用。
【问题讨论】:
【参考方案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以上是关于如何使用 Angular Http Interceptor 和 RxJS 刷新 JWT 令牌?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 angular.js 进行基本的 http 授权? [复制]
Angular2 http observables - 如何使用未定义的类型