JWT 与 Passport 授权
归档:完整、可维护的写法见 new/auth。下文为早期项目中的 JWT + Redis 校验片段。
身份验证常见流程:客户端用用户名密码登录 → 服务端签发 JWT → 后续请求在 Authorization: Bearer <token> 中携带 → Guard 校验并挂载 request.user。
安装依赖
bash
pnpm add @nestjs/jwt @nestjs/passport passport passport-jwt
pnpm add -D @types/passport-jwt
注册 JwtModule
在 AuthModule(或根模块)中注册:
ts
import { Module } from "@nestjs/common";
import { JwtModule } from "@nestjs/jwt";
@Module({
imports: [
JwtModule.register({
global: true,
secret: process.env.JWT_SECRET, // 生产环境勿硬编码
signOptions: { expiresIn: "1h" },
}),
],
})
export class AuthModule {}
使用 @nestjs/config 时推荐 registerAsync:
ts
import { ConfigModule, ConfigService } from "@nestjs/config";
JwtModule.registerAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
secret: config.getOrThrow<string>("JWT_SECRET"),
signOptions: {
expiresIn: config.get<string>("JWT_EXPIRES_IN", "1h"),
},
}),
inject: [ConfigService],
}),
Passport JWT 策略
ts
import { ExtractJwt, Strategy } from "passport-jwt";
import { PassportStrategy } from "@nestjs/passport";
import { Injectable } from "@nestjs/common";
export interface JwtPayload {
sub: string;
username: string;
}
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_SECRET,
});
}
async validate(payload: JwtPayload) {
// 返回的对象会挂载到 request.user
return { userId: payload.sub, username: payload.username };
}
}
在 AuthModule 的 providers 中注册 JwtStrategy,并 imports: [PassportModule.register({ defaultStrategy: "jwt" })]。
全局守卫与 @Public()
结合 路由守卫 中的 JwtAuthGuard 与 @Public() 装饰器,可对大部分路由默认鉴权、对登录/注册等接口放行。
若需在服务端使 token 失效(登出、踢人),可将签发后的 token 存入 Redis,在 validate 中与请求头中的 token 比对(见下方历史片段)。
可选:Redis 校验 token(历史片段)
ts
async validateToken(payload: JwtPayload, requestToken: string) {
const cached = await this.cacheService.get(`${REDIS_TOKEN_KEY}${payload.sub}`);
if (requestToken !== cached) {
throw new UnauthorizedException("登录状态已过期");
}
const userJson = await this.cacheService.get(`${REDIS_USER_INFO_KEY}${payload.sub}`);
return userJson ? JSON.parse(userJson) : { userId: payload.sub };
}
参考文献
| 资料 | 说明 |
|---|---|
| Authentication | Nest 官方认证 |
| JWT | @nestjs/jwt |
| passport-jwt | 策略实现 |