nestjs實(shí)現(xiàn)圖形校驗(yàn)和單點(diǎn)登錄的示例代碼
實(shí)現(xiàn)圖形校驗(yàn)和單點(diǎn)登錄
效果圖
前置條件
學(xué)習(xí)一下 nest
安裝
新建項(xiàng)目
npm i -g @nestjs/cli nest new project-name npm run start:dev //啟動(dòng)服務(wù)
目錄結(jié)構(gòu)
controllers
負(fù)責(zé)處理傳入的請(qǐng)求并將響應(yīng)返回給客戶端。(定義路由等)
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 請(qǐng)求和路徑 | 定義 post 請(qǐng)求和路徑 | 請(qǐng)求體(req) | 響應(yīng)體(res) | session | 獲取 req.params 參數(shù) | 獲取 req.body 參數(shù) | 獲取 req.query 參數(shù) | 獲取 req.headers 參數(shù) |
Module
@Global() @Module({ providers: [MyService], exports: [MyService], }) export class AppModule {}
- providers 屬性用來聲明模塊所提供的依賴注入 (DI) 提供者,它們將在整個(gè)模塊中共享。
- exports 屬性用于導(dǎo)出模塊中的提供者以供其他模塊使用。
- global 標(biāo)識(shí)符用于創(chuàng)建一個(gè)全局模塊。在任何地方都可以使用 @Inject() 裝飾器來注入其提供者。
- imports 選項(xiàng)用于引入其他模塊中提供的依賴關(guān)系。
service
import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { getHello(): string { return 'Hello World!'; } }
業(yè)務(wù)邏輯具體實(shí)現(xiàn)
如何生成圖形驗(yàn)證碼
需要用到 svg-captcha 這個(gè)庫(kù)
npm i svg-captcha
nest 命令行創(chuàng)建一個(gè) 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 將當(dāng)前會(huì)話的 captcha 存起來此時(shí)能通過:http://localhost:3000/captcha查看到效果圖
如何使用 session
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, }), );
接入 mongose
在本機(jī)下載 mogodb mogodb 官網(wǎng)下載
安裝 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 {}
創(chuàng)建 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);
創(chuàng)建 auth 模塊
nest g res auth
實(shí)現(xiàn)注冊(cè)和登錄方法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 生成隨機(jī)數(shù)和userId做鍵值對(duì)映射,為單點(diǎn)登錄打下基礎(chǔ)。
引入jwt 生成token進(jìn)行校驗(yàn)。
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: '驗(yàn)證碼錯(cuò)誤', }; } 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 不存在,則創(chuàng)建它 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; } }
最后創(chuàng)建一個(gè)guard,對(duì)用戶是否登錄進(jìn)行攔截判斷
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,即是否跳過校驗(yàn) 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; } }
到此這篇關(guān)于nestjs實(shí)現(xiàn)圖形校驗(yàn)和單點(diǎn)登錄的示例代碼的文章就介紹到這了,更多相關(guān)nestjs 圖形校驗(yàn)和單點(diǎn)登錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript搜索框點(diǎn)擊文字消失失焦時(shí)文本出現(xiàn)
這篇文章主要介紹了javascript實(shí)現(xiàn)搜索框點(diǎn)擊文字消失失焦時(shí)文本出現(xiàn)的效果,示例代碼如下,大家可以看看2014-09-09JavaScript使用小插件實(shí)現(xiàn)倒計(jì)時(shí)的方法講解
今天小編就為大家分享一篇關(guān)于JavaScript使用小插件實(shí)現(xiàn)倒計(jì)時(shí)的方法講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-039個(gè)讓JavaScript調(diào)試更簡(jiǎn)單的Console命令
這篇文章主要為大家詳細(xì)介紹了9個(gè)讓JavaScript調(diào)試更簡(jiǎn)單的Console命令,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11在chrome瀏覽器中,防止input[text]和textarea在聚焦時(shí)出現(xiàn)黃色邊框的解決方法
chrome瀏覽器不管對(duì)于開發(fā)者還是一般用戶都可以說是一個(gè)相當(dāng)優(yōu)秀的網(wǎng)頁(yè)瀏覽器,但是在開發(fā)中,讓人感覺很多余的一個(gè)特性就是,在表單項(xiàng)中的控件聚焦時(shí)總會(huì)出現(xiàn)一個(gè)黃色邊框2011-05-05HTML+CSS+JS實(shí)現(xiàn)抓娃娃機(jī)游戲
這篇文章主要介紹了如何利用HTML+CSS+JS制作抓娃娃機(jī)游戲,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04JavaScript中的構(gòu)造函數(shù)和實(shí)例對(duì)象之間的關(guān)系(構(gòu)造器)
這篇文章主要介紹了JavaScript中的構(gòu)造函數(shù)和實(shí)例對(duì)象之間的關(guān)系(構(gòu)造器),需要的朋友可以參考下2023-05-05Bootstrap網(wǎng)頁(yè)布局網(wǎng)格的實(shí)現(xiàn)
柵格就是網(wǎng)格,本文詳細(xì)的介紹了Bootstrap網(wǎng)頁(yè)布局網(wǎng)格的原理和實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07vue 集成騰訊地圖實(shí)現(xiàn)api(附DEMO)
之前項(xiàng)目使用騰訊地圖,不利于開發(fā)者查找,這篇文章主要介紹了vue 集成騰訊地圖實(shí)現(xiàn)api,具有一定的參考價(jià)值,感興趣的可以了解下2021-07-07