技术交流群:699951342
问题由来
我的web项目架构:Angular + ThinkPHP5,我采用了前后端分离模式,考虑项目拓展性,使用token而不使用Session。
现有解决方案
那么图形验证码的逻辑该如何设计,我搜集了许多方法:
技术 | 优点 | 缺点 | 逻辑 | 评价 | 相关网站 |
---|---|---|---|---|---|
redis | 高速缓存,提高后端响应速度 | 需要安装redis | 生成验证码1234,将其保存到redis,使用后销毁 | 若你开发的系统已经使用到了redis,可以考虑此方法。 | 点击进入. |
除此之外,验证码存数据库的解决方法可以归为第一类,redis也是数据库的一种。
我的方案
问题的根本在于如何让验证码使用后失效,也就是让验证码具有状态。
绞尽脑汁的我想通了:仅凭借逻辑代码无法让其具有状态。
我选择了ThinkPHP自带的Cache缓存,按道理说Cache缓存的实现也是一种键值数据库,Cache缓存通过写文件来实现数据库功能,虽然不如Redis读写内存响应速度快,但对图形验证码来说,足以。
改写底层逻辑
因为ThinkPHP的Captcha扩展基于Session,所以我改写了它。(没安装的请先按官网教程安装)
路径:vendor\topthink\think-captcha\src\Captcha.php
代码19行$config中的内容我做了修改,你可以安装你的偏好修改
如果你想使用自定义字体,请上传两份同样的ttf字体文件到think-captcha\assets下的ttfs和zhttfs文件夹下
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: sa<admin@mail.saylimo.com>
// +----------------------------------------------------------------------
namespace think\captcha;
use think\Cache;
class Captcha
{
protected $config = [
'seKey' => 'ThinkPHP.CN',
// 验证码加密密钥
'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY',
// 验证码字符集合
'expire' => 1800,
// 验证码过期时间(s)
'useZh' => false,
// 使用中文验证码
'zhSet' => '们惊顿挤秒悬姆烂森糖圣凹陶词借',
// 中文验证码字符串
'useImgBg' => false,
// 使用背景图片
'fontSize' => 25,
// 验证码字体大小(px)
'useCurve' => true,
// 是否画混淆曲线
'useNoise' => true,
// 是否添加杂点
'imageH' => 0,
// 验证码图片高度
'imageW' => 0,
// 验证码图片宽度
'length' => 4,
// 验证码位数
'fontttf' => '',
// 验证码字体,不设置随机获取
'bg' => [255,255,255],
// 背景颜色
'reset' => true,
// 验证成功后是否重置
];
private $_image = null; // 验证码图片实例
private $_color = null; // 验证码字体颜色
/**
* 架构方法 设置参数
* @access public
* @param array $config 配置参数
*/
public function __construct($config = [])
{
$this->config = array_merge($this->config, $config);
}
/**
* 使用 $this->name 获取配置
* @access public
* @param string $name 配置名称
* @return mixed 配置值
*/
public function __get($name)
{
return $this->config[$name];
}
/**
* 设置验证码配置
* @access public
* @param string $name 配置名称
* @param string $value 配置值
* @return void
*/
public function __set($name, $value)
{
if (isset($this->config[$name])) {
$this->config[$name] = $value;
}
}
/**
* 检查配置
* @access public
* @param string $name 配置名称
* @return bool
*/
public function __isset($name)
{
return isset($this->config[$name]);
}
/**
* 验证验证码是否正确
* @access public
* @param string $code 用户验证码
* @param string $id 验证码标识
* @return bool 用户验证码是否正确
*/
public function check($code, $id = '')
{
if (empty($code) || empty($id)) {
return false;
}
if($this->authcode(strtoupper($code)) == Cache::get($id)){
$this->reset && Cache::rm($id);
return true;
}
return false;
}
/**
* 输出验证码并把验证码的值保存的session中
* 验证码保存到session的格式为: array('verify_code' => '验证码值', 'verify_time' => '验证码创建时间');
* @access public
* @param string $id 要生成验证码的标识
* @return \think\Response
*/
public function