如何在 Nestjs 中刷新令牌
Posted
技术标签:
【中文标题】如何在 Nestjs 中刷新令牌【英文标题】:How to refresh token in Nestjs 【发布时间】:2019-04-17 04:20:09 【问题描述】:import ExtractJwt, Strategy from 'passport-jwt';
import AuthService from './auth.service';
import PassportStrategy from '@nestjs/passport';
import Injectable, UnauthorizedException from '@nestjs/common';
import JwtPayload from './model/jwt-payload.model';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy)
constructor(private readonly authService: AuthService)
super(
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'secretKey',
);
async validate(payload: JwtPayload)
const user = await this.authService.validateUser(payload);
if (!user)
throw new UnauthorizedException();
return true;
令牌是由PassportStrategy
从请求中提取的。当令牌过期或无效时,我不知道如何捕捉错误。我的目的是如果因为令牌过期而出现错误,我需要刷新令牌。否则做别的事。
【问题讨论】:
【参考方案1】:可以在自定义身份验证保护中的canActivate
方法中处理刷新令牌实现。
如果访问令牌过期,刷新令牌将用于获取新的访问令牌。在这个过程中,刷新令牌也会更新。
如果两个令牌都无效,cookie 将被清除。
@Injectable()
export class CustomAuthGuard extends AuthGuard('jwt')
private logger = new Logger(CustomAuthGuard.name);
constructor(
private readonly authService: AuthService,
private readonly userService: UserService,
)
super();
async canActivate(context: ExecutionContext): Promise<boolean>
const request = context.switchToHttp().getRequest();
const response = context.switchToHttp().getResponse();
try
const accessToken = ExtractJwt.fromExtractors([cookieExtractor])(request);
if (!accessToken)
throw new UnauthorizedException('Access token is not set');
const isValidAccessToken = this.authService.validateToken(accessToken);
if (isValidAccessToken) return this.activate(context);
const refreshToken = request.cookies[REFRESH_TOKEN_COOKIE_NAME];
if (!refreshToken)
throw new UnauthorizedException('Refresh token is not set');
const isValidRefreshToken = this.authService.validateToken(refreshToken);
if (!isValidRefreshToken)
throw new UnauthorizedException('Refresh token is not valid');
const user = await this.userService.getByRefreshToken(refreshToken);
const
accessToken: newAccessToken,
refreshToken: newRefreshToken,
= this.authService.createTokens(user.id);
await this.userService.updateRefreshToken(user.id, newRefreshToken);
request.cookies[ACCESS_TOKEN_COOKIE_NAME] = newAccessToken;
request.cookies[REFRESH_TOKEN_COOKIE_NAME] = newRefreshToken;
response.cookie(ACCESS_TOKEN_COOKIE_NAME, newAccessToken, COOKIE_OPTIONS);
response.cookie(
REFRESH_TOKEN_COOKIE_NAME,
newRefreshToken,
COOKIE_OPTIONS,
);
return this.activate(context);
catch (err)
this.logger.error(err.message);
response.clearCookie(ACCESS_TOKEN_COOKIE_NAME, COOKIE_OPTIONS);
response.clearCookie(REFRESH_TOKEN_COOKIE_NAME, COOKIE_OPTIONS);
return false;
async activate(context: ExecutionContext): Promise<boolean>
return super.canActivate(context) as Promise<boolean>;
handleRequest(err, user)
if (err || !user)
throw new UnauthorizedException();
return user;
将用户附加到请求是在JwtStrategy
类的validate
方法中完成的,如果访问令牌有效,它将被调用
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy)
constructor(
readonly configService: ConfigService,
private readonly userService: UserService,
)
super(
jwtFromRequest: cookieExtractor,
ignoreExpiration: false,
secretOrKey: configService.get('jwt.secret'),
);
async validate( id ): Promise<User>
const user = await this.userService.get(id);
if (!user)
throw new UnauthorizedException();
return user;
自定义 cookie 提取器示例
export const cookieExtractor = (request: Request): string | null =>
let token = null;
if (request && request.signedCookies)
token = request.signedCookies[ACCESS_TOKEN_COOKIE_NAME];
return token;
;
【讨论】:
这不会将用户附加到请求中 将用户附加到请求是在validate
类中的 JwtStrategy
方法中完成的,我为此添加了一个示例
cookieExtractors 来自哪里?
cookieExtractor 是一个自定义提取器,用它更新示例【参考方案2】:
您可以创建自己的AuthGuard
并覆盖请求处理程序,而不是使用内置的AuthGuard
:
@Injectable()
export class MyAuthGuard extends AuthGuard('jwt')
handleRequest(err, user, info: Error)
if (info instanceof TokenExpiredError)
// do stuff when token is expired
console.log('token expired');
return user;
根据您想要执行的操作,您还可以覆盖您有权访问请求对象的canActivate
方法。看看AuthGuard
sourcecode。
【讨论】:
我不明白。我应该如何使用这种方法将新的访问令牌传递给客户端?能详细点吗? @Albert 这确实取决于您的具体要求,但也许这个thread 会有所帮助。 令牌过期错误从何而来?以上是关于如何在 Nestjs 中刷新令牌的主要内容,如果未能解决你的问题,请参考以下文章
NestJS & Passport:更改用户密码时更改 JWT 令牌?
我在我的 nestJS 应用程序(使用 authGuard)中使用了 passport-jwt 身份验证策略,如何访问我的控制器中的令牌有效负载?