nest.js实现验证码功能

1、npm下载需要的包

安装session包

npm i express-session
npm i -D @types/express-session

安装验证码包

//安装包
npm i svg-captcha
//安装ts代码提示
npm i -D @types/@svg-captcha

 2、定义session

Session(会话)

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

import * as session from 'express-session';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.use(
    session({
      secret: 'my-secret',
      resave: false,
      saveUninitialized: false,
      rolling: true, //在每次请求时强行设置 cookie,这将重置 cookie 过期时间(默认:false)
    }),
  );

  app.setGlobalPrefix('api');

  await app.listen(3000);
}
bootstrap();

3、实现验证码接口

import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  Session,
} from '@nestjs/common';
import * as svgCaptcha from 'svg-captcha';

......

 @Get('captchaImage')
  getCode(@Session() session) {
      const captcha = svgCaptcha.create({
      size: 4, //验证码长度
      fontSize: 50,
      width: 110,
      height: 38,
      background: '#cc9966', //背景颜色
    });
    session.code = captcha.text; //session保存验证码
    return { img: captcha.data }; // aptcha.data  返回的是svg图
  }

4、前端请求获取到验证码

<template>
  <div class="login-code">
    <!-- <img :src="codeUrl" @click="getCode" class="login-code-img" /> -->
    <div @click="getCode" v-html="codeUrl" class="login-code-img"></div>
  </div>
</template>

<script>
import request from '@/utils/request'

export default {
  name: '',
  data() {
    return { codeUrl: '' }
  },
  created() {
    this.getCode()
  },
  methods: {
    getCode() {
      request({
        url: '/login/captchaImage',
        headers: {
          isToken: false
        },
        method: 'get',
        timeout: 20000
      }).then((res) => {
        this.codeUrl = res.img
      })
    }
  }
}
</script>

<style>
</style>

5、验证验证码(登录接口)

import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  Session,
} from '@nestjs/common';

import * as svgCaptcha from 'svg-captcha';


@Controller('login')
export class LoginController {
  constructor(private readonly loginService: LoginService) {}

  // 获取验证码
  @Get('captchaImage')
  getCode(@Session() session) {
    const captcha = svgCaptcha.create({
      size: 4, //验证码长度
      fontSize: 50,
      width: 110,
      height: 38,
      background: '#cc9966', //背景颜色
    });
    session.code = captcha.text; //session保存验证码
    return { img: captcha.data }; // aptcha.data  返回的是svg图
  }

  //登录接口
  @Post('signUp')
  signUp(@Session() session, @Body() body) {
    // 前端传回来的验证码,转换成小写
    const code = body.code.toLowerCase();
    //get方式获取的验证码定义的
    const sessionCode = String(session.code).toLowerCase();
    console.log(code, sessionCode);
    if (sessionCode === code) {
      return {
        code: 200,
        msg: '验证码正确',
        data: {},
      };
    } else {
      return {
        code: 601,
        msg: '验证码错误',
        data: {},
      };
    }
  }

 
}

注意:如果你是使用core来解决跨域问题,这时就会出现登录接口的session上没有保存之前验证码获取的code这个属性。

原因:

第一次接到请求,后关会生成一个sessionid来标识当前会话(我使用express-session来实现),并通过set-cookie响应头在客户端生一个cookie,大概长这样,

connect.sid=s%3Au9xG34DBU1vOVbIpCax0neMxL_Uc1fIC.4ndNJL5G%2B41DtUSLbQ%2BW75Z9wduOAON4lfu2JGTDe5
由于cookie会自动发送给服务器,所以当前用户后面的所有请求都会携带这个sessionid给服务器,服务器通过这个sessionid来标识是否为同一个用户,

但是默认情况下,标准的跨域请求是不会发送cookie等用户认证凭据的,同样,后端通过Set-Cookie在跨域时默认是被浏览器忽略的,所以这个登录接口的session跟之前验证码获取接口的session是不同的。

解决办法:

方法一

前端发起请求时设置 withCredentials:true 请求头

设置该请求头后,后端Access-Control-Allow-Origin的值不能设置为 *,必须设置为具体域名
 

// 创建axios实例
const service = axios.create({
  // axios中请求配置有baseURL选项,表示请求URL公共部分
  baseURL: process.env.VUE_APP_BASE_API,
  // 超时
  timeout: 10000,
  withCredentials: true, // 设置跨域,是否提供凭据信息(cookie、HTTP认证及客户端SSL证明等),且服务端要设置Access-Control-Allow-Origin,告诉浏览器允许跨域,而且这个值必须指定域名,不能设置为*
})
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

import * as session from 'express-session';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.enableCors({
    //  定义了被允许的请求头列表。这里指定了几个常见的请求头(如果请求头里面的自定义字段也要加上去)
    allowedHeaders: [
      'Accept',
      'Accept-Version',
      'Content-Type',
      'Api-Version',
      'Origin',
      'X-Requested-With',
      'Authorization',
      'istoken', // 添加istoken字段
    ],
    //定义了允许跨域访问的来源。可以是一个字符串,也可以是一个字符串数组
    origin: ['http://localhost:8080'],
    // 指定了是否允许跨域请求携带认证信息,如 Cookies、Authorization 等
    credentials: true,
    //  定义了响应头中可以被客户端读取的字段列表。这里只列出了一个字段名 API-Token-Expiry。
    exposedHeaders: ['API-Token-Expiry'],
  });

  app.use(
    session({
      secret: 'my-secret',
      resave: false,
      saveUninitialized: false,
      rolling: true, //在每次请求时强行设置 cookie,这将重置 cookie 过期时间(默认:false)
    }),
  );

  app.setGlobalPrefix('api');

  await app.listen(3000);
}
bootstrap();

方法二

使用vue的代理来解决跨域就没有以上的那些事。。。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,需要安装 `@nestjs/typeorm` 和 `typeorm` 依赖,用于连接数据库和操作数据库。 然后,在 Nest.js 中创建一个 Service: ```typescript import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { User } from './user.entity'; @Injectable() export class UserService { constructor( @InjectRepository(User) private readonly userRepository: Repository<User>, ) {} async findAll(): Promise<User[]> { return this.userRepository.find(); } async findOneById(id: number): Promise<User> { return this.userRepository.findOne(id); } async create(user: User): Promise<User> { return this.userRepository.save(user); } async update(id: number, user: User): Promise<User> { await this.userRepository.update(id, user); return this.userRepository.findOne(id); } async delete(id: number): Promise<void> { await this.userRepository.delete(id); } } ``` 在这个 Service 中,我们使用 `@InjectRepository(User)` 注解来注入 `User` 实体类的 Repository 对象。然后,我们定义了一些方法来操作数据库,例如 `findAll()` 方法用于查询所有用户信息,`findOneById(id: number)` 方法用于根据 id 查询用户信息,`create(user: User)` 方法用于创建用户信息,`update(id: number, user: User)` 方法用于更新用户信息,`delete(id: number)` 方法用于删除用户信息。 最后,我们需要在 Nest.js 中将这个 Service 注册为一个 Provider,例如: ```typescript import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { UserService } from './user.service'; import { UserController } from './user.controller'; import { User } from './user.entity'; @Module({ imports: [TypeOrmModule.forFeature([User])], providers: [UserService], controllers: [UserController], }) export class UserModule {} ``` 在这个 Module 中,我们使用 `TypeOrmModule.forFeature([User])` 方法来注册 `User` 实体类,并将 `UserService` 注册为一个 Provider。如果需要使用这个 Service,只需要在 Controller 中注入即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值