Как обновить токены JWT, используя Angular Http Interceptor и RxJS? - PullRequest
0 голосов
/ 12 октября 2018

Я использую два токена JWT - Refresh Token (срок действия истекает через 7 дней) и Access Token (срок действия истекает через 15 минут).Они хранятся в httpOnly cookies и доступны через сервер.Методы обновления подписывают новый токен и сохраняют его в файле 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 Ответ

0 голосов
/ 12 октября 2018

Использование mergeMap для последовательной проверки действительности токена.

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