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è)庫
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)注冊和登錄方法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 (用setTimeout而非setInterval)
javascript (用setTimeout而非setInterval)如果用setInterval 可能出現(xiàn) 下次調(diào)用會(huì)在前一次調(diào)用前調(diào)用2011-12-12
原生javaScript做得動(dòng)態(tài)表格(注釋寫的很清楚)
因?yàn)榭垂竞枚嘤脛?dòng)態(tài)表格的,所以,我就試著用js做了動(dòng)態(tài)表格,下面有個(gè)不錯(cuò)的示例,感興趣的朋友可以參考下2013-12-12
微信小程序?qū)崿F(xiàn)驗(yàn)證碼倒計(jì)時(shí)
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)驗(yàn)證碼倒計(jì)時(shí),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
微信小程序wxs日期時(shí)間處理的實(shí)現(xiàn)示例
最近在做一個(gè)列表的時(shí)候,涉及到時(shí)間格式化操作。本文主要介紹了微信小程序wxs日期時(shí)間處理的實(shí)現(xiàn)示例,分享給大家,感興趣的可以了解一下2021-07-07
javascript語句中的CDATA標(biāo)簽的意義
javascript語句中的CDATA標(biāo)簽的意義...2007-05-05

