介绍
身份验证是大多数应用的重要组成部分。有许多不同的方法和策略来处理身份验证。任何项目所采用的方法都取决于其特定的应用需求。本章介绍了几种可以适应各种不同要求的身份验证方法。
让我们充实我们的要求。对于此用例,客户端将首先使用用户名和密码进行身份验证。一旦通过身份验证,服务器将发送一个 JWT
,该 JWT
可以在后续请求的授权标头中作为 不记名令牌 发送以证明身份验证。我们还将创建一个仅供包含有效 JWT
的请求访问的受保护路由。
我们将从第一个要求开始:验证用户。然后我们将通过发布 JWT
来扩展它。最后,我们将创建一个受保护的路由来检查请求中的有效 JWT。
JWT 令牌
首先安装依赖:
1 2
| pnpm add --save @nestjs/jwt
|
安装成功之后,我们需要在auth.module.ts
中注册:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt';
@Module({ imports: [ JwtModule.register({ global: true, secret: "xxxxxxxxxxxxxxxx", signOptions: { expiresIn: '60s' }, }), ], })
|
::: warning 注意
secret
当然你可以添加在环境变量中, 如果添加到环境变量中写法如下:
:::
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { ConfigService } from '@nestjs/config'; @Module({ imports: [ JwtModule.registerAsync({ useFactory: async (configService: ConfigService) => { return { secret: configService.get<string>('JWT_SECRET'), signOptions: { expiresIn: configService.get<string>('JWT_EXPIRES_IN'), }, }; }, inject: [ConfigService], }), ], })
|
通行证/身份验证
身份验证用的第三方@nestjs/passport
, 可以看文档通行证整合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import { ExtractJwt, Strategy } from "passport-jwt"; import { PassportStrategy } from "@nestjs/passport"; import { Injectable } from "@nestjs/common"; import { Payload } from "./auth.interface"; import { Request } from "express"; import { AuthService } from "./auth.service";
@Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor(private readonly authService: AuthService) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: process.env.JWT_SECRET, passReqToCallback: true, }); }
async validate(request: Request, payload: Payload) { const authorization = request.headers.authorization || ""; const token = authorization.slice(7); const user = await this.authService.validateToken(payload, token); return user || { userId: payload.userId }; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| export class AuthService { async validateToken(payload: Payload, resToken: string) { const token = await this.cacheService.get( `${REDIS_TOKEN_KEY}${payload.userId}` ); if (resToken !== token) throw new ApiException("登录状态已过期", HttpStatusCode.FORBIDDEN); const userString = await this.cacheService.get( `${REDIS_USER_INFO_KEY}${payload.userId}` ); return userString ? JSON.parse(userString) : null; } }
|
最后将这个module
挂载在app.module.ts
中:
1 2 3 4 5 6
| @Module({ imports: [AuthModule], controllers: [], providers: [], exports: [], })
|