前言
在传统的 Web 开发过程中,处理图形验证码很简单,只需要在后台用随机字符串生成一个图片,将验证码内容放进 Session 即可,用户提交表单时从 Session[1] 取出判断即可。
但是现如今,越来越推崇 API 交互,无状态,在 Session 这一块,虽然默认配置是不支持了,但是还是有很多曲线救国的方法。
基于 Session 实现
在 API 开发中,我们也可以给前端签发 SessionID ,并且通过 PHP 的内置方法,来实现这一切。
比如 我们与前段约定,当在请求中包含有 X-Session-Id
,且不为空时,表示这个会话已经注册过 SessionID ,否则就颁布一个 SessionID 并返回在 Response Header 中的 X-Session-Id
让前段记录这个 SessionID ,下面简单实现一下。
// code_session.phpsession_start();// 这里假设已经通过 Header 获取到了 SessionID,并保存到了 $sessionId 变量中。// 当 SessionID 不存在,或者 为空 则创建新的 SessionID 。if(!isset($sessionId) || empty($sessionId)){ $sessionId = session_create_id(); // 因为前台还没有 SessionID ,所以下发一个,通知前端保存。 header('X-Session-Id: '.$sessionId);}// 设置当前会话的 SessionID 。session_id($sessionId);// 这里我们就可以自由的读写 Session 了。// 生成验证码$code = mt_rand(1e3 ,1e4-1);// create_image 请自行实现 或者使用现有的图形验证码库生成。$image = create_image($code);// 存储进去 Session$_SESSION['code'] = $code;// 输出一张图片$image->output();
上(、本文来源gao@!dai!ma.com搞$$代^@码网*搞gaodaima代码面基本实现了生成图片,前端需要根据 只需要再提交表单时,在 headers 中带上 X-Session-ID
即可。
// code_session_validate.phpsession_start();// 这里假设已经通过 Header 获取到了 SessionID,并保存到了 $sessionId 变量中。// 当 SessionID 不存在,或者 为空 则创建新的 SessionID 。if( !isset($sessionId) || empty($sessionId) || !isset($_POST['code']) || empty($_POST['code'])){ // 因为没有提交 SessionID 过来 这个肯定就是不成立的了,所以直接终止即可。 exit;}// 设置当前会话的 SessionID 。session_id($sessionId);if($_POST['code']!=$_SESSION['code']){ // 验证码错误啦 exit;}// 验证通过了就删掉 code,unset($_SESSION['code']);
上面使用 Session ,我们基本就实现了一个简单的验证,而且是基于 API 交互的,不依赖浏览器 cookie 。当我们需要一些复杂的比如共享 Session ,这些就不在本文的讨论范围了(其实现在也已经超纲了)
基于客户端主动签发
接下来的方法是无状态的,但是需要用到 Redis 。这里使用 PHPRedis 这个扩展来处理。
在大多数情况下,我们并不需要像上面使用 Session 那样来创建过多的 Session ,造成有一些资源浪费,当然,Session 可以做的不止这些,下面我们就用 Redis 来做一个客户端主动签发
的图片验证码。
理论原理
由客户端本地生成随机字符串,然后拼接在获取验证码地址的后面,后端截取客户端生成的随机字符串,用此作为验证凭证放入 Redis 中去,再客户端提交时需要带上先前生成的随机字符串一同进项验证。
// code_client.php$salt = 'wertyujkdbaskndasda';if(!isset($_GET['sign'])){ // 客户端没有提供签名,停止执行 exit;}// 用户传来的一切数据都是不可靠的,我们需要对其加盐后执行 md5$sign = md5($_GET['sign'].$salt);// 拼接上签名作为 Redis 的 key$key = 'code:'.$sign;// 连接 Redis $cache = new \Redis();// 生成验证码$code = mt_rand(1e3,1e4-1);// 保存验证码到 Redis 并设置2分钟的有效期。if($cache->exists($key)){ // 这个 Key 已经被占用了,这里先停止。 exit;}$cache->set($key,$code,60*2);// 创建图片并返回$image = create_image($code);$image->output();