nestjs实现图形校验和单点登录的示例代码

作者:Yoge 时间:2024-04-16 09:49:08 

实现图形校验和单点登录

效果图

nestjs实现图形校验和单点登录的示例代码

前置条件

学习一下 nest

安装

新建项目

npm i -g @nestjs/cli
nest new project-name
npm run start:dev //启动服务

目录结构

nestjs实现图形校验和单点登录的示例代码

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 参数

Module

@Global()
@Module({
 providers: [MyService],
 exports: [MyService],
})
export class AppModule {}
  • providers 属性用来声明模块所提供的依赖注入 (DI) 提供者,它们将在整个模块中共享。

  • exports 属性用于导出模块中的提供者以供其他模块使用。

  • global 标识符用于创建一个全局模块。在任何地方都可以使用 @Inject() 装饰器来注入其提供者。

  • imports 选项用于引入其他模块中提供的依赖关系。

service

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 命令行:

nestjs实现图形校验和单点登录的示例代码

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查看到效果图

nestjs实现图形校验和单点登录的示例代码

如何使用 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

在本机下载 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;
 }
}

来源:https://juejin.cn/post/7231846322763595836

标签:nestjs,图形校验,单点登录
0
投稿

猜你喜欢

  • 随感:交互设计两三事

    2009-05-18 13:54:00
  • js获取浏览器高度 窗口高度 元素尺寸 偏移属性的方法

    2024-04-16 08:55:16
  • SQL语句实例说明 方便学习mysql的朋友

    2024-01-22 19:48:50
  • Python2与Python3关于字符串编码处理的差别总结

    2022-05-21 19:09:51
  • python获取字符串中的email

    2021-04-23 21:23:29
  • Python实现统计给定列表中指定数字出现次数的方法

    2023-02-04 09:50:29
  • 使用python编写简单计算器

    2023-08-27 17:07:46
  • python3实现zabbix告警推送钉钉的示例

    2023-01-16 06:59:04
  • Mysql 原生语句中save or update 的写法汇总

    2024-01-13 15:08:52
  • 使用Python点云生成3D网格

    2023-02-06 18:32:45
  • JPA之映射mysql text类型的问题

    2024-01-17 06:38:41
  • PyQt5按下按键选择文件夹并显示的实现

    2023-05-02 02:02:10
  • Python pandas自定义函数的使用方法示例

    2022-05-13 02:38:35
  • Python协程asyncio异步编程笔记分享

    2022-03-05 22:23:31
  • vscode配置anaconda3的方法步骤

    2023-11-05 16:45:02
  • Dreamweaver技巧十二招

    2009-07-05 18:53:00
  • golang进程内存控制避免docker内oom

    2024-05-09 09:47:11
  • 实例解析Python设计模式编程之桥接模式的运用

    2021-06-03 18:48:04
  • Python groupby函数图文详解

    2021-10-01 06:17:09
  • 详解如何创建Python元类

    2023-09-20 04:50:15
  • asp之家 网络编程 m.aspxhome.com