前端部分
这里用的antd-vue,ui库可以自行选择 codeUrl为后端返回的图片链接 每次点击图片时把时间戳拼接在url后面达到刷新图片的功能(投机取巧) onFinish 提交数据将验证码一并提交
<template>
<a-form
:model="formState"
name="basic"
:label-col="{ span: 8 }"
:wrapper-col="{ span: 16 }"
autocomplete="off"
@finish="onFinish"
@finishFailed="onFinishFailed"
>
<a-form-item
label="Username"
name="username"
:rules="[{ required: true, message: 'Please input your username!' }]"
>
<a-input v-model:value="formState.username" />
</a-form-item>
<a-form-item
label="Password"
name="password"
:rules="[{ required: true, message: 'Please input your password!' }]"
>
<a-input-password v-model:value="formState.password" />
</a-form-item>
<a-form-item
label="验证码"
name="text"
:rules="[{ required: true, message: 'Please input your text!' }]"
>
<a-input v-model:value="formState.text" />
<img @click="resetCode" :src="codeUrl" alt="" />
</a-form-item>
<a-form-item :wrapper-col="{ offset: 8, span: 16 }">
<a-button type="primary" html-type="submit">Submit</a-button>
</a-form-item>
</a-form>
</template>
<script setup lang="ts">
import axios from "axios";
import { reactive, ref } from "vue";
interface FormState {
username: string;
password: string;
text: string;
}
const codeUrl = ref<string>("/api/user/code");
const resetCode = () => {
codeUrl.value = "/api/user/code" + "?" + +new Date();
};
const formState = reactive<FormState>({
username: "",
password: "",
text: "",
});
const onFinish = (values: any) => {
axios.post("/api/user/create", values).then((res) => {
console.log(res);
});
};
const onFinishFailed = (errorInfo: any) => {
console.log("Failed:", errorInfo);
};
</script>
后端部分
npm i express-session --save
npm i @types/express-session -D
npm install svg-captcha -S
import {
Body,
Controller,
Delete,
Get,
Param,
Patch,
Post,
Query,
Req,
Res,
} from '@nestjs/common';
import * as svgCaptcha from 'svg-captcha';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {
console.log(111);
}
//利用svg-captcha生成校验码图片并存储在前端session中
@Get('code')
createCaptcha(@Req() req, @Res() res) {
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);
}
@Post('create')
createUser(@Req() req, @Body() body) {
if (
req.session.code.toLocaleLowerCase() === body?.text?.toLocaleLowerCase() //读取前端传来的验证码和存储的验证码对比
) {
return {
message: '验证码正确',
};
} else {
return {
message: '验证码错误',
};
}
}
}