NestJS之04-session案例验证码登录

1,243 阅读2分钟

1. 什么是session

Session(会话)是指客户端与服务器之间建立的一种交互方式,通过在服务器上存储一个 session ID,来跟踪用户的状态和信息。

  1. 跟踪用户状态:通过 Session 可以识别用户是否登录、用户所在的权限组等,从而对用户进行相应的操作和控制。
  2. 存储用户信息:通过 Session 可以在服务器端存储用户信息,例如购物车信息、表单数据等,可以在不同页面和请求之间进行传递和操作。
  3. 防止重复提交:利用 Session 可以在一段时间内防止用户重复提交表单,保证数据的完整性和准确性。
  4. 用户跟踪:通过 Session 可以记录用户访问网站的行为,从而分析用户行为、优化网站设计等。

Session 存储在服务器端的内存、硬盘或数据库等地方,具体存储的位置取决于 Session 中间件的配置。

Session 的工作原理是,服务器在收到客户端的请求之后,会将一个 Session ID 发送给客户端(一般是通过 Cookie 来存储,也可以通过查询字符串或者 HTTP 头部的方式来传递),客户端在后续的请求中通过这个 Session ID 来告诉服务器自己的身份和状态。服务器在收到客户端的请求后,根据 Session ID 来读取或更新相应的 Session 数据,实现对客户端状态的跟踪和管理。

2. session使用

安装session

npm i express-session --save

npm i @types/express-session -D

main.ts 添加

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { VersioningType } from '@nestjs/common';
import * as session from 'express-session';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.enableVersioning({
    type: VersioningType.URI,
  });
  app.use(
    session({
      secret: 'yinuo', // 加密
      rolling: true,  // 每次请求添加cookie
      name: 'yn-ssid', // 存在浏览器cookie中的key
      cookie: { maxAge: null }, // 过期时间 ms 
    }),
  );
  await app.listen(3000);
}
bootstrap();

cookie的maxAge设置为1000 ,时间过了,session-Id变化了

image.png

image.png

maxAge设置为null

image.png

image.png

cookie中

image.png

3. 验证码登录案例

后端nestjs  验证码插件 svgCaptcha

npm install svg-captcha -S

前端代码:

使用 npm install element-plus -S

Login.vue

<template>
     <div class="wraps">
          <el-form :label-position="labelPosition" label-width="100px" :model="formLabelAlign" style="max-width: 460px">
               <el-form-item label="账号">
                    <el-input v-model="formLabelAlign.name" />
               </el-form-item>
               <el-form-item label="密码">
                    <el-input type="password" v-model="formLabelAlign.password" />
               </el-form-item>
               <el-form-item label="验证码">
                    <div style="display:flex">
                         <el-input  v-model="formLabelAlign.code" />
                         <img @click="resetCode" :src="codeUrl" alt="">
                    </div>
               </el-form-item>
               <el-form-item>
                    <el-button @click="submit">登录</el-button>
               </el-form-item>
          </el-form>
     </div>
</template>
     
<script setup lang='ts'>
import { onMounted, reactive, ref } from 'vue';
 
const codeUrl = ref<string>('/api/user/code')
// 默认写成图片地址,每次点击获 需要重新更新视图
const resetCode = () => codeUrl.value = codeUrl.value + '?' + Math.random()
 
const labelPosition = ref<string>('right')
 
const formLabelAlign = reactive({
     name: "",
     password: "",
     code: ""
})
 
const submit = async () => {
     await fetch('/api/user/create', {
          method: "POST",
          body: JSON.stringify(formLabelAlign),
          headers: {
               'content-type': 'application/json'
          }
     }).then(res => res.json())
}
 
 
 
</script>
     
<style>
* {
     padding: 0;
     margin: 0;
}
 
.wraps {
     display: flex;
     justify-content: center;
     align-items: center;
     height: inherit;
}
 
html,
body,
#app {
     height: 100%;
}
</style>

代理

server: {
    proxy: {
        '/api': {
            target: 'http://localhost:3000',
            changeOrigin: true,
            rewrite: path => path.replace(/^\/api/, '')
        }
    }
}

image.png

后端代码:

import * as svgCaptcha from 'svg-captcha';
@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post('create')
  createCode(@Body() body, @Req() req) {
// 判断两次的code是否相等
    if (
      body?.code?.toLocaleLowerCase() === req.session.code.toLocaleLowerCase()
    ) {
      return {
        code: 1,
        message: '验证成功',
      };
    } else {
      return {
        code: 0,
        message: '验证失败',
      };
    }
  }

  @Get('code')
  createCaptcha(@Req() req, @Res() res) {
    console.log('打印***req,res', req.session, res.type);
    //每次重新请求,会生成新的验证码
    const captcha = svgCaptcha.create({
      size: 4, //生成几个验证码
      fontSize: 50, //文字大小
      width: 100, //宽度
      height: 34, //高度
      background: '#cc9966', //背景颜色
    });
    req.session.code = captcha.text; //存储验证码记录到session
    res.type('image/svg+xml');
    res.send(captcha.data);
  }
}

image.png

image.png