koa+node+redis实现注册图片验证码功能
基本思路
- 设计图片验证码获取接口
 - 根据客户端唯一key将生成的验证码保存在redis中
 - 注册验证,根据key来获取验证码再和用户输入的验证码进行对比校验。
 
安装redis
这里我是使用的docker进行安装
docker pull redisdocker 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 -Sconst 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 -Simport { 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,
};
                            
                            
Comment here is closed