验证码
Node.js 的验证码确实很坑,底层本身不带有这些操作。查询了很多方法,大多都需要安装新的底层依赖,跨平台性非常低。而且涉及到一个很重要的问题,就是在部署的时候,你还得在部署的平台上再安装一次这个依赖。
介于以上原因,选择了一个国人产的简单的验证码生成库 node-gd-bmp。
生成验证码
1、node-gd-bmp
如何生成,参考 node-gd-bmp 文档。这里只是研究如何将生成的验证码回传给客户端。
回传一个字符串
服务器:
router.get('/captcha', function (req, res) { const img = makeCapcha(); res.setHeader('Content-Type', "text/plain"); // 设置响应头 res.end('data:image/bmp;base64,' + img.getFileData().toString('base64')); });
客户端:
axios({ url: '/security-code/captcha', method: 'GET', responseType: 'text' }).then(res => { this.setState({ vcLoding: false, captcha: res.data // 使用返回的字符串,这里是在 React 中使用 });
HTML:
// jsx 语法 <img src={captcha} src='验证码'/> // 也可用作背景 <Button style={{backgroundImage: `url(${captcha})`}} onClick={this.handleVCButtonClick}></Button>
回传一张图片
服务器:
router.get('/captcha', function (req, res) { const img = makeCapcha(); res.setHeader('Content-Type', "image/bmp"); // 设置响应头 res.end(img.getFileData()); });
客户端:
handleButtonClick = () => { let BaseUrl = '/security-code/captcha?str='; // randomStr(16) 用于获取16位的随机字符串 // 在每次点击的时候 url 都改变,以防止浏览器进行缓存 this.setState({ captcha: BaseUrl + randomStr(16) }); }
HTML:
// jsx 语法 <img src={captcha} src='验证码'/> // 也可用作背景 <Button style={{backgroundImage: `url(${captcha})`}} onClick={this.handleButtonClick} loading={vcLoding}></Button>
2、svg-captcha
生成验证码:
由于验证码会在项目中的多个使用,因此,我们将它提取到一个单独的模块:
// captcha.js
var svgCaptcha = require('svg-captcha');
// // 全局配置, 需要时将注释取消
// const options = {
// width: 100,
// height: 20,
// fontSize: 25,
// }
// Object.assign(svgCaptcha.options, options);
const makeCapcha = () => {
var captcha = svgCaptcha.create({
size: 6,
ignoreChars: '0o1i',
noise: 3,
width: 100,
height: 30,
fontSize: 25,
});
return captcha;
}
module.exports = makeCapcha;
回传 svg
服务器:
router.get('/captcha', function (req, res) { const captcha = makeCapcha(); // req.session.captcha = captcha.text; res.type('svg'); res.status(200).send(captcha.data); });
客户端:
handleButtonClick = () => { let BaseUrl = '/security-code/captcha?str='; // randomStr(16) 用于获取16位的随机字符串 // 在每次点击的时候 url 都改变,以防止浏览器进行缓存 this.setState({ captcha: BaseUrl + randomStr(16) }); }
HTML:
// jsx 语法 <img src={captcha} src='验证码'/> // 也可用作背景 <Button style={{backgroundImage: `url(${captcha})`}} onClick={this.handleButtonClick} loading={vcLoding}></Button>
除了在服务器生成验证码上有区别外,与 node-gd-bmp 用法相同。对比两者,svg-captcha 更简洁,更优美,但样式偏少;node-gd-bmp 的定制化程度更高。
验证
验证码实现的基本原理是客户端将用户填写的验证码数据与服务器上存储的数据进行比对。
在服务器上存储验证码数据有多种方式,常用的有 session、redis
session
在 session 存储验证码数据是一种常见的做法,我们在生成验证的时候会获得一个字符串,我们将此字符串存储在当前的 session 中,当用户提交验证码到服务器时,将 session 中存储的字符串与用户提交的字符串进行比对。
存储验证码:
router.get('/captcha', function (req, res) { const captcha = makeCapcha(); // 存储验证码字符串 req.session.captcha = captcha.text; res.type('svg'); res.status(200).send(captcha.data); });
验证验证码:
router.post('/sign_up', function (req, res) { if (req.body.captcha === res.session.captcha) { console.log('验证成功'); } });
redis