-
npm install
$ yarn add passport passport-jwt passport-local @nestjs/passport @nestjs/jwt -S
-
创建 auth 文件
nest g service auth logical nest g module auth logical
-
新建 auth 常量文件
// src/logical/auth/constats.ts export const jwtConstants = { secret: 'shinobi7414' // 秘钥 };
-
新建 JWT 策略
// src/logical/auth/jwt.strategy.ts import { ExtractJwt, Strategy } from 'passport-jwt'; import { PassportStrategy } from '@nestjs/passport'; import { Injectable } from '@nestjs/common'; import { jwtConstants } from './constants'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: jwtConstants.secret, }); } // JWT验证 - Step 4: 被守卫调用 async validate(payload: any) { console.log(`JWT验证 - Step 4: 被守卫调用`); return { userId: payload.sub, username: payload.username, realName: payload.realName, role: payload.role }; } }
-
编写 auth.service.ts 逻辑
// src/logical/auth/auth.service.ts import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import * as md5 from 'md5'; import { Admin } from '../../admin/entities/admin.entity'; const encryptPassword = (pw, salt) => md5(`${md5(pw)}${salt}`); @Injectable() export class AuthService { constructor(private readonly jwtService: JwtService) {} // JWT验证 - Step 2: 校验用户信息 async validateUser(user: Admin, password: string): Promise<any> { console.log('JWT验证 - Step 2: 校验用户信息'); if (user) { const hashedPassword = user.password; const salt = user.salt; // 通过密码盐,加密传参,再与数据库里的比较,判断是否相等 const hashPassword = encryptPassword(password, salt); if (hashedPassword === hashPassword) { // 密码正确 const res = this.certificate(user); console.log(res); return res; } else { // 密码错误 return { code: 2, user: null, }; } } // 查无此人 return { code: 3, user: null, }; } // JWT验证 - Step 3: 处理 jwt 签证 async certificate(user: any) { const payload = { username: user.username, sub: user.userId, realName: user.realName, role: user.role, }; console.log('JWT验证 - Step 3: 处理 jwt 签证'); try { const token = this.jwtService.sign(payload); return { code: 200, data: { token, }, msg: `登录成功`, }; } catch (error) { return { code: 600, msg: `账号或密码错误`, }; } } }
-
编辑 auth.module.ts
// src/logical/auth/auth.module.ts import { Module } from '@nestjs/common'; import { AuthService } from './auth.service'; import { JwtStrategy } from './jwt.strategy'; import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; import { jwtConstants } from './constants'; import { Admin } from '../../admin/entities/admin.entity'; import { TypeOrmModule } from '@nestjs/typeorm'; @Module({ imports: [ TypeOrmModule.forFeature([Admin]), PassportModule.register({ defaultStrategy: 'jwt' }), JwtModule.register({ secret: jwtConstants.secret, signOptions: { expiresIn: '8h' }, // token 过期时效 }), ], providers: [AuthService, JwtStrategy], exports: [AuthService], }) export class AuthModule {}
-
编辑 app.module.ts
import { AuthModule } from './logical/auth/auth.module'; // 仅增加 AuthModule 的引入, 如果 AuthService 被引入,要删除 @Module({ imports: [UserModule, AuthModule], controllers: [AppController], providers: [AppService], }) export class AppModule {}
-
编辑 user.module.ts
import { AuthModule } from 'src/logical/auth/auth.module'; // imports 仅增加 AuthModule @Module({ imports: [AuthModule], })
-
编辑 user.service.ts(我这里的模块命名为 Admin)
// 增加导入 import { AuthService } from 'src/logical/auth/auth.service'; @Injectable() export class AdminService { constructor( @InjectRepository(Admin) private admin: Repository<Admin>, // 增加声明 private readonly authService: AuthService, ) {} async login({username, password}: {username: string; password: string}) { const user = await this.admin.findOne({ where: { username, }, }); // 增加登录校验 const data = await this.authService.validateUser(user, password) return data; } }
-
编辑 user.controller.ts
import { Get, Query, Bind, UseGuards, } from '@nestjs/common'; import { AdminService } from './admin.service'; import { Admin } from './entities/admin.entity'; import { AuthGuard } from '@nestjs/passport'; @Controller('admin') export class AdminController { constructor(private readonly adminService: AdminService) {} // 增加路由守卫 @UseGuards(AuthGuard('jwt')) @Get('/detail') @Bind(Query()) findOne(query: { id?: number; mobile?: string; email?: string }) { return this.adminService.findOne(query); } }
-
创建自定义守卫 @Public,再也不用傻傻地每个接口地写
@UseGuards(AuthGuard('jwt'))
啦-
创建装饰器文件
// /src/common/decorator/public.decorator.ts import { SetMetadata } from '@nestjs/common'; export const Public = () => SetMetadata('isPublic', true);
-
创建全局守卫
-
创建 guard 文件
// /src/common/guards/auth.guard.ts import { ExecutionContext, Injectable } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; @Injectable() export class JwtAuthGuard extends AuthGuard('jwt') { constructor(private reflector: Reflector) { super(); } canActivate(context: ExecutionContext) { const isPublic = this.reflector.getAllAndOverride('isPublic', [ context.getHandler(), context.getClass(), ]); if (isPublic) return true; return super.canActivate(context); } }
-
编辑 app.module.ts
// /src/app.module.ts import { resolve } from 'path'; import { Module, MiddlewareConsumer, RequestMethod } from '@nestjs/common'; import { ConfigModule } from 'nestjs-config'; import { ScheduleModule } from '@nestjs/schedule'; import { APP_GUARD } from '@nestjs/core'; import { JwtAuthGuard } from './common/guards/auth.guard'; @Module({ imports: [ ], providers: [ { provide: APP_GUARD, useClass: JwtAuthGuard, }, ], }) export class AppModule { configure(consumer: MiddlewareConsumer) {} }
-
-
使用 @public
import { Controller, Get, Post, Body, Param, Request } from '@nestjs/common'; import { Public } from 'src/common/decorator/public.decorator'; import { AuthorizationService } from './authorization.service'; @Controller('canteenApp/authorization') export class AuthorizationController { constructor(private readonly authorizationService: AuthorizationService) {} // 在公开的接口里声明 @Public() 就不用走鉴权了 @Public() @Post('/login') async login(@Body() body) { return await this.authorizationService.login(body.username, body.password); } }
-
-
已完成
参考
Nest.js 从零到壹系列(三):使用 JWT 实现注册、登录 juejin.cn/post/684490…
NestJS jwt实现token验证,并使用自定义Guard来使无需专门每个接口配置Guard鉴权 blog.csdn.net/baidu_39340…
nest.js学习笔记(五) --jwt验证 www.cnblogs.com/venblogs/p/…