Laravel、ThinkPHP使用poster扩展包实现图片的旋转验证、滑块验证
使用Composer安装
composer require kkokk/poster
生成海报
use Kkokk\Poster\Facades\Poster; // 使用 Facades\Poster 调用 // 头像链接 $avatar = 'https://portrait.gitee.com/uploads/avatars/user/721/2164500_langlanglang_1601019617.png'; $poster = Poster::config([ 'path' => __DIR__ . '/poster.png' // 设置图片保存地址、图片文件名、图片类型 ]) ->buildIm(638, 826, [41, 43, 48, 1], false) // 创建一个 638 * 826 的空白画布 ->buildImage($avatar, 253, 326, 0, 0, 131, 131, false, 'circle') // 添加一个头像上去 ->buildText('苏轼', 'center', 477, 16, [255, 255, 255, 1]) // 再来点文字 ->buildText( '明月几时有,把酒问青天。不知天上宫阙,今夕是何年。', 'center', 515, 14, [255, 255, 255, 1] ) ->getPoster(); // 最后获取海报地址
滑块验证码
use Kkokk\Poster\Facades\Captcha; // 使用 Facades\Poster 调用 /** * 获取滑块验证图片 * @return array 返回格式如下 * img 是base64格式的图片 * key 是验证时需要使用的值 * y 是前端渲染滑块的高度 * secret 是正确的密钥(在没有内置缓存的情况下会返回) */ $result = Captcha::type('slider')->get(); // 获取验证参数 /** * 滑块验证 * @param string $key * @param string $value 滑动位置的值 * @param int $leeway 允许的误差值 * @param int $secret 返回的密钥(如果前面没返回这个参数,这里就不用传) * @return bool true 验证成功 false 失败 */ $check = Captcha::check($key, $value, $leeway, $secret);
参考文档:
http://www.520yummy.com/poster-doc/guide/v2/
前端实现:
http://www.520yummy.com/poster-doc/guide/v2/features/captcha/#%E5%89%8D%E7%AB%AF%E5%AE%9E%E7%8E%B0
gitee:
https://gitee.com/langlanglang/poster
github:
https://github.com/kkokk/poster
滑块演示:
https://kkokk.github.io/captcha/
滑块图片验证
# 自定义参数 $params = [ 'src' => '', // 背景图片,尺寸 340 * 191 'im_width' => 340, // 画布宽度 'im_height' => 251, // 画布高度 'im_type' => 'png', // png 默认 jpg quality 质量 'quality' => 80, // jpg quality 质量 'bg_width' => 340, // 背景宽度 'bg_height' => 191, // 背景高度 'slider_width' => 50, // 滑块宽度 'slider_height' => 50, // 滑块高度 'slider_border' => 2, // 滑块边框 'slider_bg' => 1, // 滑块背景数量 ]; $type = 'slider'; /** * 获取验证参数 * 内部使用了 laravel 的 cache 缓存,返回的是图片的 base64 、 缓存key 、滑块高度 * @param string $type 验证码类型 * @param array $params 验证码自定义参数 * @return arary */ $data = PosterManager::Captcha()->type($type)->config($params)->get(); $data = Captcha::type($type)->config($params)->get(); /** * 验证 * 前端根据相关滑块操作进行处理, 返回x坐标,返回 true 则验证成功 * @param string $key 缓存key * @param string|int $value 前端传回来的x坐标 * @param int $leeway 误差值 * @return boolean */ $res = PosterManager::Captcha()->type($type)->check($key, $value, $leeway); $res = Captcha::type($type)->check($key, $value, $leeway);
旋转图片验证
# 自定义参数 $params = [ 'src' => '', // 背景图片,尺寸 350 * 350 正方形都可 'im_width' => 350, // 画布宽度 'im_height' => 350, // 画布高度 'im_type' => 'png', // png 默认 jpg quality 质量 'quality' => 80, // jpg quality 质量 ]; $type = 'rotate'; /** * 获取验证参数 * 内部使用了 laravel 的 cache 缓存,返回的是图片的 base64 、 缓存key * @param string $type 验证码类型 * @param array $params 验证码自定义参数 * @return arary */ $data = PosterManager::Captcha()->type($type)->config($params)->get(); $data = Captcha::type($type)->config($params)->get(); /** * 验证 * 前端根据相关滑块操作进行处理, 返回x坐标,返回 true 则验证成功 * @param string $key 缓存key * @param string|int $value 前端传回来的旋转角度 * @param int $leeway 误差值 * @return boolean */ $res = PosterManager::Captcha()->type($type)->check($key, $value, $leeway); $res = Captcha::type($type)->check($key, $value, $leeway);
点击图片验证
# 自定义参数 $params = [ 'src' => '', 'im_type' => 'png', // png 默认 jpg quality 质量 'quality' => 80, // jpg quality 质量 'font_family' => '', // 感谢站酷提供免费商用站酷库黑体、可自定义炫酷字体文件(绝对路径) 'contents' => '', // 自定义文字 'font_count' => 0, // 文字长度 'font_size' => 42, // 字体大小 'line_count' => 0, // 干扰线数量 'char_count' => 0, // 干扰字符数量 ]; $type = 'click'; /** * 获取验证参数 * 内部使用了 laravel 的 cache 缓存,返回的是图片的 base64 、 缓存key * @param string $type 验证码类型 * @param array $params 验证码自定义参数 * @return arary */ $data = PosterManager::Captcha()->type($type)->config($params)->get(); $data = Captcha::type($type)->config($params)->get(); /** * 验证 * 前端根据相关点击操作进行处理, 返回点击坐标数组,返回 true 则验证成功 * @param string $key 缓存key * @param string|int|array $value 前端传回来的坐标数组 * @return boolean */ $res = PosterManager::Captcha()->type($type)->check($key, $value); $res = Captcha::type($type)->check($key, $value);
手动输入验证
# 自定义参数 $params = [ 'src' => '', 'im_width' => 256, 'im_height' => 64, 'im_type' => 'png', // png 默认 jpg quality 质量 'quality' => 80, // jpg quality 质量 'type' => 'number', // type = number 数字 alpha_num 字母和数字 math 计算 text 文字 'font_family' => '', // 可自定义炫酷字体文件 'font_size' => 32, // 字体大小 'font_count' => 4, // 字体长度 'line_count' => 5, // 干扰线数量 'char_count' => 10, // 干扰字符数量 ]; $type = 'input'; /** * 获取验证参数 * 内部使用了 laravel 的 cache 缓存,返回的是图片的 base64 、 缓存key * @param string $type 验证码类型 * @param array $params 验证码自定义参数 * @return arary */ $data = PosterManager::Captcha()->type($type)->config($params)->get(); $data = Captcha::type($type)->config($params)->get(); /** * 验证 * 前端根据相关输入, 返回输入结果,返回 true 则验证成功 * @param string $key 缓存key * @param string|int|array $value 输入结果 * @return boolean */ $res = PosterManager::Captcha()->type($type)->check($key, $value); $res = Captcha::type($type)->check($key, $value);
前端实现
参考仓库
gitee
github
js
直接引入js
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>图片验证DEMO</title>
</head>
<body>
<button type="button" onclick="captcha()">
验证
</button>
</body>
</html>
<script type="text/javascript" src="./slider/slider-min.js"></script>
滑块验证 js
<script type="text/javascript"> // 开始验证 function captcha(){ // 根据 poster 获取验证参数 Slider = new langSlider({ title: '滑块安全验证', start: function(Slider) { setTimeout(function(){ Slider.sliderStart({ sliderBg: './slider/img/slider.png', sliderKey: '1212', sliderY: 46 }) }, 1000); }, check: function(sliderKey, sliderX, Slider) { // 模拟调用验证接口 const check = () => { const leeway = 5 // 误差值 const value = 208 // 正确值 if(value >= (sliderX - leeway) && value <= (sliderX + leeway)){ // 成功调用该方法 Slider.sliderSuccess() } else { // 错误调用该方法 // 模拟调用获取验证参数接口 setTimeout(function(){ Slider.sliderError({ sliderBg: './slider/img/slider.png', sliderKey: '1212', sliderY: 46 }) }, 1000); } } setTimeout(function(){ check() }, 1000) }, refresh: function(Slider){ setTimeout(function(){ Slider.sliderRefresh({ sliderBg: './slider/img/slider.png', sliderKey: '1212', sliderY: 46 }) }, 1000); }, }) } </script>
vue
安装
npm install @kkokk/captcha
yarn add @kkokk/captcha
卸载
npm uninstall @kkokk/captcha
yarn remove @kkokk/captcha
引入
// main.js 引入 import Captcha from '@kkokk/captcha' Vue.use(Captcha)
调用
<template> <div id="app"> <button @click="open">验证</button> <slider-captcha v-model="visible" :options="options" :loading="loading" @check="check" @close="close" @refresh="getSliderOptions" @error="getSliderOptions" > /** vue2 */ <span slot="title">自定义标题-安全验证</span> <span slot="successText">自定义成功提示-登录中</span> <span slot="errorText">自定义错误提示-是不是太难了换一个</span> <span slot="tips">自定义提示拖动下方滑块完成拼图</span> /** vue2 */ /** vue3 */ <template #title>自定义标题-安全验证</template> <template #successText>自定义成功提示-登录中</template> <template #errorText>自定义错误提示-是不是太难了换一个</template> <template #tips>自定义提示拖动下方滑块完成拼图</template> /** vue3 */ </slider-captcha> </div> </template> <script> export default { name: 'App', data(){ return { visible: false, loading: false, options: {} } }, methods: { // 打开触发 open() { this.visible = true this.getSliderOptions() }, // 验证 check(sliderKey, sliderX, done, error) { // 这里应该是验证是否成功的接口 if(sliderX > 208 - 5 && sliderX < 208 + 5) { // 验证成功 done() } else { // 验证错误 error() } }, // 关闭触发 close() { }, // 获取滑块验证参数 getSliderOptions() { this.loading = true this.request({ type: 'get', url: 'http://127.0.0.1:8111/', success: (res) => { this.options = { sliderImg: res.img, sliderKey: res.key, sliderY: res.y } this.loading = false } }) }, // 封装一个简单请求接口,方便测试 request(obj) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest(); switch(obj.type) { case 'get': xhr.open('GET', obj.url, true); xhr.onload = function() { resolve(obj.success(JSON.parse(this.responseText))) }; xhr.onError= function () { reject(obj.error({ status: this.status, statusText: xhr.statusText })); }; break; case 'post': xhr.open('POST', obj.url, true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onreadystatechange = function() { if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { resolve(obj.success(JSON.parse(this.responseText))) } }; break; } xhr.send(JSON.stringify(obj.data)); }); } } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>


浙公网安备 33010602011771号