Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登陆(SSO)场景。JWT的声明通常被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也能够增长一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。web
咱们都知道,http协议自己是无状态的协议,若是在一个系统中,咱们只有登陆后在能够操做,因为http是无状态的,因此那就必须每一个接口都须要一个认证,来查看当前用户是否有权限。今天咱们就基于以前的项目,集成JWT。数据库
1 user.service方法
增长一个查询单个用户的方法,这个方法不须要对应控制器。安全
async findOne(name: string): Promise<any | undefined> { const user = await this.UserRepository.findOne({ where: { name: name, }, }); if (user == undefined) { return void 0; } else { return user; } }
2 增长登陆路由
在user.controller文件中新增路由,里面的逻辑暂时什么都不写服务器
@Post('/login') async login(@Body() loginParmas: any) {}
3 安装依赖网络
yarn add passport passport-jwt passport-local @nestjs/passport @nestjs/jwt -S
4 建立Auth模块
src下新建文件夹logical/auth,auth目录下为咱们逻辑功能。
constants.ts - 常量async
export const jwtConstants = { secret: 'NestAPI', };
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) { return { id: payload.id, name: payload.name, nickname: payload.nickname, }; } }
auth.service.ts - 验证逻辑ide
import { Injectable, Inject } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { UserService } from '../../user/user.service'; import { encryptPassword } from '../../utils/cryptogram'; @Injectable() export class AuthService { constructor( @Inject('UserService') private readonly usersService: UserService, private readonly jwtService: JwtService, ) {} // JWT验证 - Step 2: 校验用户信息 async validateUser(name: string, password: string): Promise<any> { const user = await this.usersService.findOne(name); if (user) { const hashedPassword = user.password; const salt = user.passwdSalt; // 经过密码盐,加密传参,再与数据库里的比较,判断是否相等 const hashPassword = encryptPassword(password, salt); if (hashedPassword === hashPassword) { // 密码正确 return { code: 1, user, }; } else { // 密码错误 return { code: 2, user: null, }; } } // 查无此人 return { code: 3, user: null, }; } // JWT验证 - Step 3: 处理 jwt 签证 async certificate(user: any) { const payload = { id: user.id, name: user.name, nickname: user.nickname, }; try { const token = this.jwtService.sign(payload); return { code: 200, data: { token, }, msg: `登陆成功`, }; } catch (error) { return { code: 600, msg: `帐号或密码错误`, }; } } }
auth.module.tspost
import { Module } from '@nestjs/common'; import { AuthService } from './auth.service'; import { JwtStrategy } from './jwt.strategy'; import { UserModule } from '../../user/user.module'; import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; import { jwtConstants } from './constants'; @Module({ imports: [ PassportModule.register({ defaultStrategy: 'jwt' }), JwtModule.register({ secret: jwtConstants.secret, signOptions: { expiresIn: '8h' }, // token 过时时效 }), UserModule, ], providers: [AuthService, JwtStrategy], exports: [AuthService], }) export class AuthModule {}
上面这些属于配置,调用咱们须要在路由/login里面写逻辑,第2步中咱们只定义了一个空的方法,咱们接下来写逻辑测试
import { ApiTags, ApiParam, ApiQuery, ApiHeader } from '@nestjs/swagger'; import { Controller, Post, Body, Logger, HttpCode, UseGuards, } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { AuthService } from '../logical/auth/auth.service'; import { UserService } from './user.service'; @ApiTags('用户管理') @Controller('user') export class UserController { constructor( private readonly authService: AuthService, private readonly userService: UserService, ) {} /** * 用户登陆 */ @Post('/login') async login(@Body() loginParmas: any) { const authResult = await this.authService.validateUser( loginParmas.name, loginParmas.password, ); switch (authResult.code) { case 1: return this.authService.certificate(authResult.user); case 2: return { code: 600, msg: `帐号或密码不正确`, }; default: return { code: 600, msg: `当前用户未查到`, }; } } }
5 测试
运行项目,咱们用postman测试