您好,登錄后才能下訂單哦!
本篇文章和大家了解一下nestjs實現圖形校驗和單點登錄的方法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有所幫助。
效果圖
學習一下 nest
新建項目
npm i -g @nestjs/cli nest new project-name npm run start:dev //啟動服務
目錄結構
controllers
負責處理傳入的請求并將響應返回給客戶端。(定義路由等)
import { Controller, Get } from '@nestjs/common'; @Controller() export class AppController { constructor() {} @Get() getHello(): string { return 'hello world'; } }
controllers 常用裝飾器
常用裝飾器
@Controller(path) | @Get(path) | @Post(path) | @Request(), @Req() | @Response(), @Res() | @Session() | @Param(key?: string) | @Body(key?: string) | @Query(key?: string) | @Headers(name?: string) |
---|---|---|---|---|---|---|---|---|---|
定義 root 路徑 | 定義 get 請求和路徑 | 定義 post 請求和路徑 | 請求體(req) | 響應體(res) | session | 獲取 req.params 參數 | 獲取 req.body 參數 | 獲取 req.query 參數 | 獲取 req.headers 參數 |
@Global() @Module({ providers: [MyService], exports: [MyService], }) export class AppModule {}
providers 屬性用來聲明模塊所提供的依賴注入 (DI) 提供者,它們將在整個模塊中共享。
exports 屬性用于導出模塊中的提供者以供其他模塊使用。
global 標識符用于創建一個全局模塊。在任何地方都可以使用 @Inject() 裝飾器來注入其提供者。
imports 選項用于引入其他模塊中提供的依賴關系。
import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { getHello(): string { return 'Hello World!'; } }
業務邏輯具體實現
需要用到 svg-captcha 這個庫
npm i svg-captcha
nest 命令行創建一個 captcha 模塊nest g res captchanest 命令行:
import { Controller, Get, Response, Session } from '@nestjs/common'; import * as svgCaptcha from 'svg-captcha'; @Controller('captcha') export class CaptchaController { @Get() async getCaptcha(@Response() res, @Session() session) { const captcha = svgCaptcha.create({ size: 4, noise: 2, }); session.captcha = captcha.text; res.type('svg'); res.send(captcha.data); } }
通過 session 將當前會話的 captcha 存起來此時能通過:http://localhost:3000/captcha查看到效果圖
npm i express-session npm i -D @types/express-session
并且再 main.ts 中引入
import * as session from 'express-session'; // somewhere in your initialization file app.use( session({ secret: 'my-secret', resave: false, saveUninitialized: false, }), );
在本機下載 mogodb mogodb 官網下載
安裝 mongoose
npm install --save mongoose
在 app.modele 中引入
import { Module } from '@nestjs/common'; import { MongooseModule } from '@nestjs/mongoose'; import { AppController } from './app.controller'; import { AppService } from './app.service'; @Module({ imports: [MongooseModule.forRoot('mongodb://127.0.0.1:27017/nest')], controllers: [AppController], providers: [AppService], }) export class AppModule {}
創建 schemas
import { Document } from 'mongoose'; import * as mongoose from 'mongoose'; export interface User { account: string; password: string; } export interface UserDoc extends User, Document {} export const UserSchema = new mongoose.Schema({ password: { type: String, required: true }, account: { type: String, required: true, unique: true, }, }); export const UserModel = mongoose.model<UserDoc>('User', UserSchema);
創建 auth 模塊
nest g res auth
實現注冊和登錄方法controller
import { Controller, Get, Body, Post, UseInterceptors, Req, Request, Res, } from '@nestjs/common'; import { AuthService } from './auth.service'; import { CreateUserDto } from './dto/index'; import { ApiCreatedResponse } from '@nestjs/swagger'; import { CaptchaMiddleware } from 'src/middleware/captcha-middleware/captcha-middleware.middleware'; @Controller('auth') export class AuthController { constructor(private readonly authService: AuthService) {} @ApiCreatedResponse({ description: 'The record has been successfully created.', type: CreateUserDto, }) @Post('register') async created(@Body() data: CreateUserDto) { const user = await this.authService.created(data); return user; } @UseInterceptors(CaptchaMiddleware) @Post('login') async login( @Body() data: CreateUserDto, @Req() request: Request, @Res() res, ) { const user = await this.authService.login(data, request); res.sendResponse(user); } }
引入uuid 生成隨機數和userId做鍵值對映射,為單點登錄打下基礎。
引入jwt 生成token進行校驗。
import { Injectable, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import mongoose, { Model } from 'mongoose'; import { InjectModel } from '@nestjs/mongoose'; import { UserDoc } from '../schemas/user.schema'; import { loginMapDoc } from '../schemas/login.mapping'; import { CreateUserDto } from './dto/index'; import { v4 as uuid } from 'uuid'; @Injectable() export class AuthService { constructor( private jwtService: JwtService, @InjectModel('user') private readonly userModel: Model<UserDoc>, @InjectModel('loginmapModel') private readonly loginmapModel: Model<loginMapDoc>, ) {} async created(data: CreateUserDto) { const user = await new this.userModel(data); return user.save(); } async login(data: any, req) { const { account, password, code } = data; if (code.toLocaleLowerCase() !== req.session?.captcha.toLocaleLowerCase()) { return { code: 400, message: '驗證碼錯誤', }; } const user = await this.userModel.findOne({ account, password, }); if (!user) { throw new UnauthorizedException(); } const loginId = uuid(); const payload = { userId: user.id, username: user.account, loginId: loginId, }; const token = this.jwtService.sign(payload); const foundCollection = await mongoose.connection.collections[ 'loginmapModel' ]; if (!foundCollection) { // 如果該 collection 不存在,則創建它 await new this.loginmapModel(); console.log('新建成功'); } await this.loginmapModel.findOneAndUpdate( { userId: user.id }, { userId: user.id, loginId }, { upsert: true, new: true, runValidators: true }, ); return { token, loginId }; } async viladate(data: any) { const { userId, loginId } = data; const map = await this.loginmapModel.findOne({ userId, loginId }); return loginId == map.loginId; } }
最后創建一個guard,對用戶是否登錄進行攔截判斷
nest g gu middleware/auth
import { CanActivate, ExecutionContext, Injectable, Request, UnauthorizedException, } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { JwtService } from '@nestjs/jwt'; import { jwtConstants } from '@/auth/constants'; import { AuthService } from '@/auth/auth.service'; @Injectable() export class AuthGuardGuard implements CanActivate { constructor( private jwtService: JwtService, private reflector: Reflector, private authService: AuthService, ) {} async canActivate(context: ExecutionContext): Promise<boolean> { const skipAuth = this.reflector.get<boolean>( 'skipAuth', context.getHandler(), ); // 返回 Boolean 值或 undefined,即是否跳過校驗 if (skipAuth) { return true; } const request: Request = context.switchToHttp().getRequest(); const token = this.extractTokenFromHeader(request); if (!token) { throw new UnauthorizedException(); } try { const payload = await this.jwtService.verifyAsync(token, { secret: jwtConstants.secret, }); const isRemoteLogin = await this.authService.viladate(payload); console.log(isRemoteLogin, 'payload', payload); if (!isRemoteLogin) { throw new UnauthorizedException('異地登錄'); } // ???? We're assigning the payload to the request object here // so that we can access it in our route handlers request['user'] = payload; } catch { throw new UnauthorizedException(); } return true; } private extractTokenFromHeader(request: any): string | undefined { const [type, token] = request.headers.authorization?.split(' ') ?? []; return type === 'Bearer' ? token : undefined; } }
以上就是nestjs實現圖形校驗和單點登錄的方法的簡略介紹,當然詳細使用上面的不同還得要大家自己使用過才領會。如果想了解更多,歡迎關注億速云行業資訊頻道哦!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。