Laravel 12 实现拖动验证码功能
在 Laravel 12 中实现拖动验证码(滑块验证码)功能,可以使用第三方服务或自行开发。以下是几种实现方式:
方法一:使用第三方服务(推荐)
1. 使用极验(GeeTest)
composer require gee-team/gt3-php-sdk
在 .env
中添加:
GEETEST_ID=your_id
GEETEST_KEY=your_key
控制器代码:
use GeeTeam\GeeValidate;
public function getGeeTest()
{
$geeValidate = new GeeValidate(env('GEETEST_ID'), env('GEETEST_KEY'));
return $geeValidate->preProcess();
}
public function validateGeeTest(Request $request)
{
$geeValidate = new GeeValidate(env('GEETEST_ID'), env('GEETEST_KEY'));
if (!$geeValidate->validate($request->input('geetest_challenge'), $request->input('geetest_validate'), $request->input('geetest_seccode'))) {
return back()->withErrors(['captcha' => '验证失败']);
}
// 验证通过
}
前端代码:
<script src="//static.geetest.com/static/tools/gt.js"></script>
<div id="geetest-captcha"></div>
<script>
initGeetest({
gt: "{{ $gt }}",
challenge: "{{ $challenge }}",
product: "float",
offline: false
}, function(captchaObj) {
captchaObj.appendTo("#geetest-captcha");
captchaObj.onSuccess(function() {
// 验证通过后的处理
});
});
</script>
2. 使用腾讯云验证码
composer require tencentcloud/tencentcloud-sdk-php
控制器代码:
use TencentCloud\Captcha\V20190722\CaptchaClient;
use TencentCloud\Captcha\V20190722\Models\DescribeCaptchaResultRequest;
use TencentCloud\Common\Credential;
public function validateTencentCaptcha(Request $request)
{
$cred = new Credential(env('TENCENT_SECRET_ID'), env('TENCENT_SECRET_KEY'));
$client = new CaptchaClient($cred, "ap-guangzhou");
$req = new DescribeCaptchaResultRequest();
$req->CaptchaType = 9; // 滑块验证码类型
$req->Ticket = $request->input('ticket');
$req->UserIp = $request->ip();
$req->Randstr = $request->input('randstr');
$req->CaptchaAppId = env('TENCENT_CAPTCHA_APP_ID');
$req->AppSecretKey = env('TENCENT_CAPTCHA_APP_KEY');
$resp = $client->DescribeCaptchaResult($req);
if ($resp->CaptchaCode != 1) {
return back()->withErrors(['captcha' => '验证失败']);
}
// 验证通过
}
方法二:自行开发简单滑块验证码
1. 后端实现
创建验证路由:
Route::post('/verify-slider', function(Request $request) {
$position = $request->input('position');
$savedPosition = session('slider_position');
// 允许±5像素的误差
if (abs($position - $savedPosition) > 5) {
return response()->json(['success' => false]);
}
session(['slider_verified' => true]);
return response()->json(['success' => true]);
});
Route::get('/slider-data', function() {
$position = rand(20, 80); // 生成随机位置(百分比)
session(['slider_position' => $position]);
return response()->json([
'position' => $position,
'image' => 'path/to/background-image.jpg' // 背景图路径
]);
});
2. 前端实现
<div class="slider-container">
<div class="slider-bg">
<img src="" id="slider-bg" alt="验证背景">
</div>
<div class="slider">
<div class="slider-btn"></div>
<div class="slider-track"></div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
fetch('/slider-data')
.then(response => response.json())
.then(data => {
document.getElementById('slider-bg').src = data.image;
const sliderBtn = document.querySelector('.slider-btn');
const sliderTrack = document.querySelector('.slider-track');
let isDragging = false;
let startX = 0;
let currentX = 0;
sliderBtn.addEventListener('mousedown', (e) => {
isDragging = true;
startX = e.clientX;
document.addEventListener('mousemove', onDrag);
document.addEventListener('mouseup', onDragEnd);
});
function onDrag(e) {
if (!isDragging) return;
currentX = e.clientX - startX;
if (currentX < 0) currentX = 0;
if (currentX > sliderTrack.offsetWidth - sliderBtn.offsetWidth) {
currentX = sliderTrack.offsetWidth - sliderBtn.offsetWidth;
}
sliderBtn.style.transform = `translateX(${currentX}px)`;
}
function onDragEnd() {
isDragging = false;
document.removeEventListener('mousemove', onDrag);
document.removeEventListener('mouseup', onDragEnd);
// 验证
const position = (currentX / (sliderTrack.offsetWidth - sliderBtn.offsetWidth)) * 100;
fetch('/verify-slider', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify({ position: position })
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('验证成功');
} else {
alert('验证失败');
sliderBtn.style.transform = 'translateX(0)';
}
});
}
});
});
</script>
方法三:使用开源库(如SlideCaptcha)
- 安装前端库:
npm install slide-captcha --save
- 前端组件:
import SlideCaptcha from 'slide-captcha';
const captcha = new SlideCaptcha({
container: '#captcha-container',
width: 320,
height: 160,
sliderL: 42,
sliderR: 9,
sliderY: 50,
onSuccess: function() {
// 验证成功回调
},
onFail: functionfunction() {
// 验证失败回调
},
onRefresh: function() {
// 刷新验证码回调
}
});
Laravel 后端验证:
public function validateSlide(Request $request)
{
$data = $request->validate([
'captcha_token' => 'required',
'slide_x' => 'required|numeric'
]);
// 这里应该添加更复杂的验证逻辑
$expected = Cache::get('captcha_'.$data['captcha_token']);
if (abs($data['slide_x'] - $expected) > 5) {
return response()->json(['success' => false]);
}
return response()->json(['success' => true]);
}
安全建议
- 对于生产环境,建议使用成熟的第三方服务
- 自行实现时,应该:
- 添加时间限制(如5分钟内完成验证)
- 限制尝试次数
- 记录失败尝试
- 使用加密令牌防止伪造
- 考虑添加行为分析,如拖动速度、路径等
以上方法可以根据项目需求选择,第三方服务通常更安全可靠但可能有费用,自行开发则更灵活但安全性需要更多考虑。