前言

最近在实现一个登录中常见的功能:图片验证码。这个功能非常有意思,但是你说难又不会太难,简单又不会太简单。不会太难之处在于你最方便可以客户端本地存储验证码图片(不排除被打的可能),不会太简单的是要做到非常完整的流程还是要点精力,比如过期时间,加密验证,签发私钥…。本文从一个不是非常主后端的角度去实现一个标准图片验证码的流程。

已用技术:

  • koa
  • koa-session(express 的原理一样)
  • svg-captcha
  • redis

原理

我们都知道正常的登录验证码都是存在一定过期时间的,那这个过期怎么算是过期?那我们可以通过 cookie,session,redis 中去判断过期与否。因为这三者在 web 和 app 都可以设定过期时间限制登录凭证。考虑用 session 和 redis 来实现这个功能,因为 cooile 太容易被篡改了。

基本思路如下:

1.用户进入登录页面后请求接口从后端获取图片验证码标签
2.后端生成验证码的同时,设置一个 session,同时拿到响应的 session 值作为 key 值,图片验证码的正确字符串作为 value,映射到 redis 中存储。
3.用户确定登录后,携带客户端的 cooile 和验证码一起发送给后台
4.后台拿到请求头中 cooile 中的 session 值和验证码,用 session 值作为 key 获取 redis 中的对应的 value 值,进行验证比对正确。

实现

后端服务器下载koa-session,redis,svg-captcha插件依赖。

后端: 在app.js中引入koa-session

const Koa = require("koa");
const session = require("koa-session");const session_signed_key = ["appletSystem"];
const app = new Koa();
const CONFIG = {name: "sessionId",maxAge: 180000, // session 过期时间,以毫秒ms为单位计算 overwrite: true,//是否允许重写 。(默认是 true) httpOnly: true,//是否设置HttpOnly,如果在Cookie中设置了"HttpOnly"属性,那么通过程序(JS脚本、Applet等)将无法读取到Cookie信息,这样能有效的防止XSS攻击。signed: true,//是否签名。(默认是 true) rolling: false,//是否每次响应时刷新Session的有效期renew: false,//是否在Session快过期时刷新Session的有效期
};
app.keys = session_signed_key;
app.use(session(CONFIG, app));app.listen(8080, () => {console.log(`服务器8080启动成功`);
});

在这里,session_signed_key为开启sign签发的公钥,CONFIG为session的配置文件,signed为了防止客户端的cookie被篡改,必须为true;maxAge为过期时间,最后设置app.keys,use(session(CONFIG, app))就ok了。

使用redis:

确保本地安装了redis并且启动服务

const { createClient } = require("redis");
const client = createClient({host: "localhost", //   redis地址port: 6379, // 端口号
});
client.on("connect", (error) => {if (!error) {console.log("connect to redis");}
});
function setString(key, value, expire = 180) { //存储key和value键值对return new Promise((resolve, reject) => {client.set(key, value, (error, replay) => {if (error) {reject("设置失败");}if (expire) {//默认expire过期时间为180sclient.expire(key, expire); //给当前的key设置过期时间}resolve("设置成功");});});
}
function getString (key) => {return new Promise(async (resolve, reject) => {client.get(key, function (err, result) {resolve(result);//直接获取value值,如果没有key,直接返回null});});
};

引入redis并且创建client代理,通过封装两个方法get和set去获取redis的key-value。方法可直接复制使用。

在验证码接口:

const svgCaptcha = require("svg-captcha");class svg {async getsvg(ctx, next) {const { time } = ctx.request.query;const c = svgCaptcha.create({size: 4, // 验证码长度ignoreChars: "0o1iLl", // 验证码字符中排除 0o1icolor: true, // 验证码是否有彩色noise: 0, //干扰线background: "#666", // 背景颜色height: 50,fontSize: 60,width: 100,});ctx.session.sessionId= { time: "svgIsMjc" + time};await ctx.session.manuallyCommit();const cookie = ctx.response.headers["set-cookie"];if (cookie) {let cookies = cookie[0]; //获取第一个值const newSessionKey = getCookie(cookies); //传字符串try {const result = await setString(newSessionKey, c.text.toLowerCase());} catch (error) {throw new Error(error);}}ctx.body = c.data;}
}

在这里遇到问题比较多,既然返回图片的时候设置一个过期的session,那么该怎么设置?起初我设置了ctx.session.sessionId= { time: “svgIsMjc” + time +ip },time为当前时间毫秒和获取的ip地址来确保session的值各不相同。

如图,确实能在图片返回的同时客户端存储了cookie值,并且为session。

并且每次请求客户端的sessionId会不同

如图

在验证图片码过期中间件接口:

const verifySvgCode = async (ctx, next) => {const cookie = ctx.request.headers.cookie;//获取cookieconst { vaildcode } = ctx.request.body;//获取客户端的验证码if (!ctx.session.sessionId) {//验证是否过期或者被篡改const error = new Error(erroType.SVG_COOKIE_IS_TIMEOUT);return ctx.app.emit("error", error, ctx);}if (cookie) {//存在就是cookie没有过期,验证cookie的redis存储的值const newSessionKey = getCookie(cookie);//转化session字符串截取sessionid值const oldvaildcode = await getString(newSessionKey);//获取value值if (oldvaildcode && vaildcode.toLowerCase() == oldvaildcode) {//校验两者验证码的相等与否,否则抛出错误await next();return;} else {const error = new Error(erroType.SVG_COOKIE_IS_FALSE);return ctx.app.emit("error", error, ctx);}} else {const error = new Error(erroType.SVG_COOKIE_IS_TIMEOUT);return ctx.app.emit("error", error, ctx);}
};

通过ctx.headers获取cookie,如果过期当前肯定为空值。在这里,我一开始是犯错误。ctx.session.sessionId是一个undefined。因为在CONFIG中我少配置了一个key属性,所以拿不到,搞得排查了大半天!。

const CONFIG = {...key: "sessionId", //cookie的key。 (默认是 koa:sess) */,必须加key值,不然无法获取session!
};

而且,还有一个npm仓库中redis工具的问题。目前redis最高为4.0版本,第二个版本就是3.1.2。在node里面使用最高4.0版本是连接不上去redis的,所以我采用3.1.2版本。

而3.1.2版本的redis工具get方法我是出现问题。 直接可以set但是get的时候总是null 我在redis-cli下却可以get到值。排查了半天,我发现是get的时候key值长度问题。

封装的截取sessionId的方法:

const getCookie = (cookie) => {//接收字符串const sessionId = cookie;const start = sessionId.indexOf("=") + 1;const end = sessionId.indexOf(";") - 2;const newSessionKey = sessionId.substring(start, 110);console.log(newSessionKey);return JSON.stringify(newSessionKey);
};

我多次调试完,发现client.get的时候传入的key值也就是sessionId的值如果超过110长度,那么redis预期这个key值不存在就给我返回null了。

所以我妥协了,截取了110长度作为key存储,再用get的时候能得到存储的value值。 如图成功拿到了。问题都在百度搜查过,存在但是没有解决办法。

总结

1.redis的创建以及使用
2.koa-session的使用方法以及注意事项
3.npm中的redis工具的get问题
4.图片验证码的流程以及校验

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

Node中实现一个简易的图片验证码流程相关推荐

  1. Android 中编写一个简易购物车,商品包括商品名称,单价,数量,可以对商品进行增删改查功能。(ArrayList,SQLite)

    Android 中编写一个简易购物车,商品包括商品名称,单价,数量,可以对商品进行增删改查功能.(ArrayList,SQLite) 布局(activity_main.xml): <?xml v ...

  2. python 图片自动分类机_用tensorflow神经网络实现一个简易的图片分类器

    文章写的不清晰请大家原谅QAQ 这篇文章我们将用 CIFAR-10数据集做一个很简易的图片分类器. 在 CIFAR-10数据集包含了60,000张图片.在此数据集中,有10个不同的类别,每个类别中有6 ...

  3. 在html中加入一个动态图,图片上加gif图片 图片某个角落贴个gif动态图,如何在静态图片上面加一张GIF动态图...

    喜欢上网的小伙伴就会知道网上流传灰常广泛一种搞笑gif动态图片,这类图片大部分是视频转gif的,就是截取视频经典搞笑画面制作而成,还加了些搞笑文字.使用网络聊天工具尤其是QQ就最常见了,那些搞笑的表情 ...

  4. 页面中color颜色值_计算机毕业设计中实现一个简易美观的登录界面

    点击上方"蓝字",关注我们. 实现一个登录界面,展示一下效果: 然后我们看一下代码: 在我们做一个页面之前,要先想好他的一个整体布局,也就是我们这里面的login.html主页面, ...

  5. 用mysql + node搭建一个简易工作列表网站

    初衷 增删改查是web开发最常见的操作,那么接下来这篇文章将演示如何用node + mysql做一个简易的网站. 需要的知识 本教程不涉及express等web框架,但请确保您对node + mysq ...

  6. node中使用短信验证功能(阿里云为例)

    一.选择短信平台 短信平台有很多,这里我选择阿里云,详细步骤如下: 进入短信控制台,对要发送的短信格式进行配置,如果没有签名,需要申请签名后操作(注意:需要自己已有阿里云账号且实名认证成功) 按照如下 ...

  7. 文件一另存为电脑就卡住_文件太多怎么办?用Excel做一个简易目录!轻松管理多个文件...

    作为一只社畜,电脑中肯定都是各种各样的文件,文件一多,就不好管理,这时候我们可以在Excel中制作一个简易的文件目录,点击对应的链接就可以打开文件!想知道怎么做吗?一起来学一学吧! 一.目录设置 1. ...

  8. python 登陆网站图片验证,用python登录带弱图片验证码的网站

    上一篇介绍了使用python模拟登陆网站,但是登陆的网站都是直接输入账号及密码进行登陆,现在很多网站为了加强用户安全性和提高反爬虫机制都会有包括字符.图片.手机验证等等各式各样的验证码.图片验证码就是 ...

  9. Django使用图片验证码加邮箱或手机号登录

    实现页面效果 实现思路 使用form渲染数据 校验手机号(格式.是否注册).密码以及验证码 生成图片验证码 ''' pillow:是python处理图片的模块,很强大 ''' import rando ...

最新文章

  1. vue更新data中的数据页面不渲染_vue更新obj类data的属性无效,页面data没刷新解决方法vue.set...
  2. 高效学习Oracle的方法论
  3. 对象的继承关系在数据库中的实现方式和PowerDesigner设计
  4. 信息系统项目管理师-信息系统立项管理核心知识点思维脑图
  5. 【白皮书下载】《追本数源•开启产品智能化时代》| 产品指数级增长手册
  6. QML基础类型之font
  7. .Net Framwork概述
  8. 除自身以外数组的乘积leetcode 238
  9. 步进电机驱动控制器,电动云台控制。
  10. git 版本控制~ 文件没有绿色和红色图标
  11. BZOJ3083遥远的国度
  12. 半导体行业深度报告:从应用到行业的全面复苏
  13. 【Linux】常见错误 “cp: omitting directory”解决办法
  14. 一个简单的方法修复ubuntu引导损坏
  15. php雅思老师,雅思口语话题:最喜欢的老师
  16. 【开发工具】JetBrains
  17. 递 归 ,递 推 ,贪 心,学 习 总 结
  18. 在线教育平台的数据分析——用户的地域分布
  19. 一个类似JQuery的精简版框架
  20. 说好的团队为质量负责呢?

热门文章

  1. 使用原生实现tab切换+slideToggle效果
  2. 【设计】】MOS管衬底电位接法|PMOS、NMOS衬底连接-KIA MOS管
  3. 机器学习与神经影像:评估它在精神病学中的应用
  4. 百度局域网异常访问屏蔽策略破解方法
  5. 奥巴马演讲雷人文言文版
  6. VSC/SMC(一)——基于趋近律的滑模控制(含程序模型)
  7. 已下载TensorFlow却为什么无法调用?
  8. 高德地图发布全国美食地图:火锅最受欢迎
  9. 计算机应用考试U8,全国专业技术人员计算机应用能力考试考前冲刺:用友财务(U8)软件...
  10. 开发大数据“读心术”,易车深挖用户价值