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 安裝依賴markdown
yarn add passport passport-jwt passport-local @nestjs/passport @nestjs/jwt -S
4 建立Auth模塊
src下新建文件夾logical/auth,auth目錄下爲咱們邏輯功能。
constants.ts - 常量網絡
export const jwtConstants = { secret: 'NestAPI', };
jwt.strategy.ts - 驗證策略async
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 - 驗證邏輯分佈式
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.tside
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步中咱們只定義了一個空的方法,咱們接下來寫邏輯post
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測試