feat: 注册验证码改为自动生成图形验证码

1. Common.php: 新增captcha()接口,生成算术验证码图片(base64)
2. Common.php: 新增checkCaptcha()静态方法,验证码校验+防重放
3. User.php: 注册接口移除邮箱/短信OTP验证,改用图形验证码
验证码5分钟过期,验证后立即销毁
This commit is contained in:
li
2026-03-31 10:53:33 +08:00
parent 6a8ab13b7f
commit 733982a2be
2 changed files with 97 additions and 8 deletions
+87
View File
@@ -325,6 +325,93 @@ class Common extends Api
return $key;
}
/**
* 注册验证码图片 - 生成算术验证码并返回base64图片
* GET /api/common/captcha
*/
public function captcha()
{
$a = mt_rand(1, 20);
$b = mt_rand(1, 20);
$operators = ['+', '-'];
$op = $operators[array_rand($operators)];
if ($op == '-' && $a < $b) {
// 确保减法结果非负
$tmp = $a; $a = $b; $b = $tmp;
}
$answer = ($op == '+') ? ($a + $b) : ($a - $b);
$text = "{$a} {$op} {$b} = ?";
// 生成唯一key标识本次验证码
$captcha_key = md5(uniqid(mt_rand(), true));
// 将答案存入缓存(使用ThinkPHP缓存,5分钟过期)
cache('captcha_' . $captcha_key, strval($answer), 300);
// 生成验证码图片
$width = 200;
$height = 60;
$img = imagecreatetruecolor($width, $height);
// 背景色
$bgColor = imagecolorallocate($img, 240, 244, 250);
imagefilledrectangle($img, 0, 0, $width, $height, $bgColor);
// 干扰线
for ($i = 0; $i < 5; $i++) {
$lineColor = imagecolorallocate($img, mt_rand(100, 200), mt_rand(100, 200), mt_rand(100, 200));
imageline($img, mt_rand(0, $width), mt_rand(0, $height), mt_rand(0, $width), mt_rand(0, $height), $lineColor);
}
// 干扰点
for ($i = 0; $i < 50; $i++) {
$dotColor = imagecolorallocate($img, mt_rand(100, 255), mt_rand(100, 255), mt_rand(100, 255));
imagesetpixel($img, mt_rand(0, $width), mt_rand(0, $height), $dotColor);
}
// 文字颜色
$textColor = imagecolorallocate($img, mt_rand(10, 80), mt_rand(10, 80), mt_rand(10, 80));
// 使用内置字体绘制文字
$fontSize = 5; // imagestring内置字体最大5
$textWidth = imagefontwidth($fontSize) * strlen($text);
$textHeight = imagefontheight($fontSize);
$x = ($width - $textWidth) / 2;
$y = ($height - $textHeight) / 2;
imagestring($img, $fontSize, $x, $y, $text, $textColor);
// 输出为base64
ob_start();
imagepng($img);
$imgData = ob_get_clean();
imagedestroy($img);
$base64 = 'data:image/png;base64,' . base64_encode($imgData);
$this->success('ok', [
'captcha_key' => $captcha_key,
'captcha_img' => $base64,
]);
}
/**
* 验证注册验证码(内部调用)
*/
public static function checkCaptcha($captcha_key, $captcha_code)
{
if (empty($captcha_key) || empty($captcha_code)) {
return false;
}
$answer = cache('captcha_' . $captcha_key);
if ($answer === false || $answer === null) {
return false;
}
$result = (trim($captcha_code) === trim($answer));
// 验证后立即删除,防止重放
cache('captcha_' . $captcha_key, null);
return $result;
}
/**
* 生成随机key secrit
*/
+10 -8
View File
@@ -141,21 +141,23 @@ class User extends Api
$mobile = $this->request->post('mobile',"");
$m_prefix = $this->request->post('m_prefix',"");
$code = $this->request->post('code');
$captcha_key = $this->request->post('captcha_key', '');
$pwd2 = $this->request->post('pay_pwd');
$referral_code = $this->request->post('referral_code', '');
// 验证图形验证码(替代邮箱/短信OTP)
if (!$captcha_key || !$code) {
$this->error(__('验证码错误'));
}
$captchaOk = \app\api\controller\Common::checkCaptcha($captcha_key, $code);
if (!$captchaOk) {
$this->error(__('验证码错误'));
}
if($mobile){
$ret = Sms::check($mobile, $code, 'register');
if (!$ret && $code!=157258) {
$this->error(__('验证码错误'));
}
$username = $mobile;
$extend['m_prefix'] = $m_prefix;
}else{
$ret = Ems::check($email, $code, 'register');
if (!$ret && $code!=157258) {
$this->error(__('验证码错误'));
}
$username = $email;
$extend['m_prefix'] = "";
}