koa+node+redis实现注册图片验证码功能
基本思路
- 设计图片验证码获取接口
- 根据客户端唯一key将生成的验证码保存在redis中
- 注册验证,根据key来获取验证码再和用户输入的验证码进行对比校验。
安装redis
这里我是使用的docker进行安装
docker pull redis
docker run --restart=always --log-opt max-size=100m --log-opt max-file=2 -p 16380:6379 --name myredis -v /root/redis/redis.conf:/etc/redis/redis.conf -v /root/redis/data:/data -d redis redis-server /etc/redis/redis.conf --appendonly yes --requirepass 151545
上述文件目录请自行创建 最后一个参数是设置密码,保证远程连接的安全性
连接redis
node中使用到了redis这个库
npm install redis -S
const redis = require("redis");
const config = require("./config");
const client = redis.createClient({
socket: {
port: config.REDIS_PORT,
host: config.APP_HOST,
},
password: config.REDIS_PASSWORD,
});
// 监听连接事件
client
.connect()
.then(() => {
console.log("redis连接成功");
})
.catch((err) => {
console.log(err || "redis连接出错");
});
// 操作方法封装 get set
function setString(key, value, expire) {
return new Promise((resolve, reject) => {
client
.set(key, value)
.then((res) => {
if (expire) {
client.expire(key, expire);
}
console.log("设置成功");
resolve(res);
})
.catch((err) => {
console.log("设置失败");
reject(err);
});
});
}
function getString(key) {
return new Promise((resolve, reject) => {
if (key) {
client
.get(key)
.then((res) => {
resolve(res);
})
.catch((err) => {
console.log(`获取${key}失败`);
reject(err);
});
}
});
}
module.exports = {
setString,
getString,
};
验证码获取接口
首先验证码的生成我们选择svg-captcha
这个库
代码如下:
const captcha = require("svg-captcha");
function createCaptcha(config = {}) {
return captcha.create({
size: 4,
ignoreChars: "0o1iIl", // 避免生成容易混淆的字符
noise: 3,
color: true,
background: "#f4f4f4",
fontSize: 60,
...config,
});
}
module.exports = {
createCaptcha,
};
验证码接口:
const { createCaptcha } = require("../utils/createCaptcha");
const { setString } = require("../app/redis");
class CaptchaController {
async create(ctx) {
// 获取用户传递过来的唯一key
const { sid: captchaKey } = ctx.request.body;
// 生成验证码
const code = createCaptcha();
// 存储在redis中 设置过期事件 过期取出来的值为null
await setString(captchaKey, code.text, 60 * 3);
// 设置相应头
ctx.type = "image/svg+xml";
ctx.body = code.data;
}
}
module.exports = new CaptchaController();
路由中引入即可:
const { create } = require("../controller/captcha.controller");
// ...省略部分代码
// 获取验证码
authRouter.post("/captcha", create);
前端展示验证码图片
uuid生成唯一key
npm install uuid -S
import { v4 as uuidv4 } from 'uuid';
const sid = uuidv4();
// 获取图片,这里我是使用转为blob url方式
const getCathchaImage = async (sid: string) => {
// 获取验证码接口 这里的sid是一个唯一key 可以使用uuid生成
const res = await getCaptcha({ sid });
const blob = new Blob([res], {
type: 'image/svg+xml',
});
const fileURL = URL.createObjectURL(blob);
// 这里的fileURL就可以设置到img标签上的src属性
//...
};
<!--我使用的react-->
<img src={fileURL}/>
验证二维码
这里我是写了个中间件设置再注册接口中。
const { getString } = require("../app/redis");
const { omit } = require("../utils/omit");
const ResponseErrorMessage = require("../constants/responseErrorMessage");
const authCaptcha = async (ctx, next) => {
//获取传递过来的key和验证码
const { sid, captcha } = ctx.request.body;
// 判断是否为空
if (!sid || !captcha) {
const error = new Error(ResponseErrorMessage.PARAMETER_ABSENT);
return ctx.app.emit("error", error, ctx);
}
try {
// 根据唯一key从redis中获取验证码
const code = await getString(sid);
// 过期?
if (!code) {
const error = new Error(
ResponseErrorMessage.VERIFICATION_CODE_HAS_EXPIRED
);
return ctx.app.emit("error", error, ctx);
// 不区分大小写
} else if (code.toLowerCase() !== captcha.toLowerCase()) {
const error = new Error(ResponseErrorMessage.VERIFICATION_CODE_ERROR);
return ctx.app.emit("error", error, ctx);
} else {
// 验证通过
await next();
}
} catch (error) {
console.log(error);
}
};
module.exports = {
authCaptcha,
};