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

 更新时间:2023年05月12日 16:21:04   作者:Yoge  
本文主要介绍了nestjs实现图形校验和单点登录的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

实现图形校验和单点登录

效果图

login.gif

前置条件

学习一下 nest

安装

新建项目

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

目录结构

1683793619743.jpg

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

image.png

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

image.png

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

到此这篇关于nestjs实现图形校验和单点登录的示例代码的文章就介绍到这了,更多相关nestjs 图形校验和单点登录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用javascript创建快捷方式的简单实例

    使用javascript创建快捷方式的简单实例

    这篇文章介绍了使用javascript创建快捷方式的简单实例,有需要的朋友可以参考一下
    2013-08-08
  • 如何在js代码中消灭for循环实例详解

    如何在js代码中消灭for循环实例详解

    for循环对大家来说都不陌生,下面这篇文章主要给大家介绍了关于如何在js代码中消灭for循环的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
    2018-07-07
  • javascript中闭包概念与用法深入理解

    javascript中闭包概念与用法深入理解

    这篇文章主要介绍了javascript中闭包概念与用法,结合实例形式深入分析了javascript中闭包的概念、使用方法与相关注意事项,需要的朋友可以参考下
    2016-12-12
  • webpack中的热刷新与热加载的区别

    webpack中的热刷新与热加载的区别

    本篇文章主要介绍了webpack中的热刷新与热加载的区别,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • jquery form表单获取内容以及绑定数据

    jquery form表单获取内容以及绑定数据

    这篇文章主要介绍了jquery form表单获取内容以及form表单绑定数据,获取表单的数据保存到数据库,或者将数据绑定到form表单,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • 微信小程序实现点赞业务

    微信小程序实现点赞业务

    这篇文章主要为大家详细介绍了微信小程序实现点赞业务,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-02-02
  • 使用snowfall.jquery.js实现爱心满屏飞的效果

    使用snowfall.jquery.js实现爱心满屏飞的效果

    这篇文章主要介绍了使用snowfall.jquery.js实现爱心满屏飞的效果的相关资料,需要的朋友可以参考下
    2017-01-01
  • fetch跨域问题的使用详解

    fetch跨域问题的使用详解

    这篇文章主要介绍了fetch跨域问题的使用详解,fetch 的核心主要包括:Request , Response , Header , Body,利用了请求的异步特性 --- 它是基于 promise 的,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • JS获取本地文件并进行网络传输的代码详解

    JS获取本地文件并进行网络传输的代码详解

    在web中如想要获取用户计算机上的文件我们通常会用到的方法是通过一个表单元素<input type="file">操作用户选择的文件,本文小编给大家介绍了JS获取本地文件并进行网络传输的方法,需要的朋友可以参考下
    2024-08-08
  • JS实现的五级联动菜单效果完整实例

    JS实现的五级联动菜单效果完整实例

    这篇文章主要介绍了JS实现的五级联动菜单效果,结合完整实例形式分析了js多级联动菜单的完整实现步骤,涉及JS数组遍历、扩展及元素节点操作相关技巧,需要的朋友可以参考下
    2017-02-02

最新评论