今天,我想和大家分享一个在分布式系统中的验证码登录方案。随着前后端分离架构的普及,传统的 session 验证码机制已经难以适应现代Web应用的需求。
本文将结合 PHP 超高性能框架 webman 和我的开源插件 tinywan/captcha,详细讲解如何实现高效、安全的分布式验证码登录。希望这篇文章能帮助你快速上手,并在实际项目中应用。
在传统Web项目中,验证码通常依赖 session 存储。前端请求服务端生成验证码,后端将其保存在 session 上下文中,登录时直接验证用户名、密码和验证码。这种方式简单,但存在局限性:前后端耦合紧密,不利于分布式部署和微服务架构。
随着业务升级,前后端分离成为主流:前端使用Vue/React,后端专注API服务。这时,session不再可靠,我们需要引入Redis作为中间件来存储验证码状态,并使用token机制处理认证。这不仅提升了系统的可扩展性,还确保了跨域和分布式环境下的安全性。
下面,我将从传统方案入手,逐步过渡到分布式解决方案,并通过实际案例演示。
传统方案的核心是session上下文,整个流程高度依赖后端渲染页面。
这种方案适合单体应用,但前后端分离后,session跨域问题和页面跳转逻辑会变得棘手。
在分布式环境中,我们引入Redis存储验证码(取代session),并生成唯一标识符(key)来关联请求。同时,登录成功后返回token,前端负责页面跳转。
对比传统方案,增加了Redis和key机制,确保分布式一致性。
这一方案解耦了前后端,适用于微服务和云部署环境。
为了让大家上手更轻松,我以webman框架为例,集成我的开源插件tinywan/captcha
。该插件专为webman设计,支持Base64图片验证码生成和验证,无需文件存储,轻量高效。
插件地址:https://www.workerman.net/plugin/33
在webman项目根目录执行:
composer require tinywan/captcha
安装后,Composer会自动加载依赖。确保你的PHP环境支持GD或Imagick扩展(用于图片生成)。
插件使用Captcha::base64()
方法生成Base64编码的验证码,直接嵌入HTML标签。
示例控制器代码(IndexController.php):
<?php
/**
* @desc IndexController
* @author Tinywan(ShaoBo Wan)
*/
declare(strict_types=1);
namespaceapp\home\v1\controller;
usesupport\Request;
usesupport\Response;
class IndexController
{
/**
* @desc: 图片验证码
* @param Request $request
* @return Response
* @throws \Exception
* @author Tinywan(ShaoBo Wan)
*/
publicfunction captcha(Request $request): Response
{
$captcha = \Tinywan\Captcha\Captcha::base64();
return json($captcha);
}
}
访问http://127.0.0.1:8288/home/v1/index/captcha
,响应示例:
{
"key": "$2y$10$3bSPqTNT33WdwOQnG7TXQOfqlTBJKhv5AwcDFrQZQxuGKVArJcszy",
"base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPoAAAA+BAMAAADwuxusAAAAG1BMVEXz+/5NND7e4uaLfoa0sLZhTFbJyc6gl552ZW6wM8bHAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACjUlEQVRYhe1Xz2/TMBgtzq8eeWyFHROJDY4rIMEx2ei4LkNDPbZoII4N07QdG2kT/NmznXrMnyvFcYJ28TtVX/35+fv17IxGHh4eHh4eFBdPSf4LufVadvDlw6DkMXBqufLyDsCkJ99Pyv7Kzq+ARD/yK5Lp2jacIdh/AIeaYQmsrDyXgnveq+480VhrljHwwso1A07SPtyj0T5wq2/Bz7Njrouvj6jpGeBKrvwq7NK/plt2DUvgHbFFwMKNPFDh1WK+dLKMdgKPnJNjjxh5iXI39gLfmh8ldi5LPazALHwlu5tw8XUrdnGddiZnUI09lftOUv1PEmbSzNbasJ7DzFM7xg+Myy0bV7SgESZ5CDzXNwkbV0tl1PdH026bsF7qZPI0N6kyJDgTWSLssSM7a/xWzUEm74m4JvI0s0cJOU5FqxCeZpd53pWdB7c72wTPPqc8/fqEl7zwM5IQHjvl4cLgIjc88Yes/jfWSzL0XMGvVGkUeJ5PyDYlOZ8dYnkvRg96zqdZH7GoGYT8kYmJ4SCXX20qlQX2ZVID1elvajo2oUEuVoNeP1Pbu5h4CfaxatepKey1wRSao8ELuOVCaEPYRFGoiKfmlcpV4DcxlX+OqQoVhvhaIJN5/QSlKYVxf/C8GKYD2YypfkaHZ1WNDTYnjxfGEkYjl4iI1GcODxuuJXtvt+m2jafG7nLB8xOficfb+W1Xz4Dof+TAXooIMpd2zQhb/NF477QhkfOVObTr69LlyAb7qWjXruw3fyFK1heVKF53oZBDkvZmj8ULvLtEC42we+e3g94r7ajxdTEQOev+JGHfB+KWUr8ebLPOCGy/1f4LEufPkEFQ9fzs7od4/pTsHh4eHh4efXEP4hlXg7Y3KSYAAAAASUVORK5CYII="
}
key
:唯一标识,用于后续验证。base64
:图片数据,可直接用于<img src="...">
。预览图片:复制base64到浏览器或在线工具(如https://tool.jisuapi.com/base642pic.html)查看。
示例验证码图片:
或者浏览器直接输出
在登录接口中使用Captcha::check()
验证:
use Tinywan\Captcha\Captcha;
$code = $request->get('code'); // 用户输入的验证码
$key = $request->get('key'); // 之前生成的验证码 key
if (false === Captcha::check($code, $key)) {
// 验证失败
return '验证码错误';
}
// 验证通过,返回token或其他逻辑
return '验证码正确';
验证通过后,可生成JWT token返回给前端,实现无状态认证。
这个分布式验证码登录方案的优势显而易见:
在我的实际项目中,这个方案已帮助多个团队提升了登录安全性。如果你正开发webman项目,不妨试试tinywan/captcha插件。
欢迎在评论区分享你的经验,或关注我的GitHub(https://github.com/Tinywan)获取更多开源资源。