nestjs实现图形校验和单点登录的示例代码
作者:Yoge 发布时间:2024-04-16 09:49:08
标签: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 参数 |
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 命令行:
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查看到效果图
如何使用 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


猜你喜欢
- 本节要讲解如下图所示的滑块验证码(更为复杂的滑动拼图验证码在下一篇介绍)。这种验证码机制比较简单:将滑块拖动到滑轨的最右端即可完成验证,如下
- 本文为大家分享了MySQL 5.7版本的安装使用详细教程,更改数据库data的存储路径,供大家参考,具体内容如下因为看到mysql5.7加入
- 当发现目录时出错如下:\windows\tensorflow\core\framework\op_kernel.cc:993] Not fo
- 默认值可以很方便众所周知,在Python中如果访问字典中不存在的键,会引发KeyError异常(JavaScript中如果对象中不存在某个属
- 1. 问题描述:同目录下,当多个文件之间有相互依赖的关系的时候,import无法识别自己写的模块,PyCharm中提示No Module.2
- 首先我们来看个示例:<form name="buyerForm" method="post"
- mechanize是对urllib2的部分功能的替换,能够更好的模拟浏览器行为,在web访问控制方面做得更全面。结合beauti
- window.showModalDialog() 使用方法:var returnValue = window.showModalDialog
- 我看blog里,还有很多地方都引用过我写的这个类,转了不少,但自己一直也没发表过,这次正式发表一下。在蓝色理想中有人不懂怎么用,我在baid
- 每次找安装教程太麻烦,因此给自己备份一下步骤,方便以后查看。解压版下载地址https://dev.mysql.com/downloads/m
- 做软件开发时基本都会涉及到数据的使用,比如最简单用户登录注册,这用户信息则需要使用数据库做存储管理。而在项目开发测试过程最常使用的数据库则是
- 1. 新建项目在命令行窗口下输入scrapy startproject scrapytest, 如下然后就自动创建了相应的文件,如下2. 修
- 用ASP判断一个字符串中只包含字母和数字要怎么做啊? for s=1 to len(trim(use
- 人们对于产品设计这类事情,往往容易眼高手低,在宇宙层面上夸夸其谈,却落不了地,只能飘着。真正到了自己动手的时候,才会发现问题很多,实践和理论
- 数据表都已经创建起来了,假设我们已经插入了许多的数据,我们就可以用自己喜欢的方式对数据表里面的信息进行检索和显示了,比如说:可以象下面这样把
- 1,使用save会在package.json中自动添加。npm install node-sass --save-devnpm instal
- 1.新建一个vs2003的web工程,取名为XMLTest &nbs
- 前言为了介绍python语言中pandas库在数据分析中的重要作用,本人打算以NBA球星勒布朗詹姆斯在2020-2021赛季常规赛个人数据为
- 在MySQL数据库中导出整个数据库:1.导出整个数据库mysqldump -u 用户名 -p 数据库名 > 导出的文件名mysqldu
- 使用session保持用户登陆连接在 view 中 login() 视图函数里增加如下语句不允许重复登录语句if request.sessi