LazySlideCaptcha是基于.Net Standard 2.1的滑动验证码模块。项目同时提供一个基于vue2的演示前端组件和背景图裁剪工具。
【码云地址】 | 【Github 地址】
图形验证码请移步lazy-captcha。
在线体验点这里
Install-Package Lazy.SlideCaptcha.Core
dotnet add package Lazy.SlideCaptcha.Core
builder.Services.AddSlideCaptcha(builder.Configuration); // 如果使用redis分布式缓存 //builder.Services.AddStackExchangeRedisCache(options => //{ // options.Configuration = builder.Configuration.GetConnectionString("RedisCache"); // options.InstanceName = "captcha:"; //});
"SlideCaptcha": { "Backgrounds": [ { "Type": "file", "Data": "wwwroot/images/background/1.jpg" }, { "Type": "file", "Data": "wwwroot/images/background/2.jpg" } ] }
背景图片要求尺寸要求为 552 X 344 , 快速开始可在 Demo 项目 wwwroot/images/background 下挑选。(仅用作演示,生产请自行制作。)也可以通过裁剪工具制作,非常简单,上传图片,拖动范围后保存自动生成 552 X 344 图片。
[Route("api/[controller]")] [ApiController] public class CaptchaController : ControllerBase { private readonly ICaptcha _captcha; public CaptchaController(ICaptcha captcha) { _captcha = captcha; } /// <summary> /// id /// </summary> /// <param name="id"></param> /// <returns></returns> [Route("gen")] [HttpGet] public CaptchaData Generate() { return _captcha.Generate(); } /// <summary> /// id /// </summary> /// <param name="id"></param> /// <returns></returns> [Route("check")] [HttpPost] public bool Validate([FromQuery]string id, SlideTrack track) { return _captcha.Validate(id, track); } }
至此后端Api服务已搭建完成。
@{ ViewData["Title"] = "滑动验证码"; } <link rel="stylesheet" href="~/lib/lazy-slide-captcha/dist/lazy-slide-captcha.css" asp-append-version="true" /> <style> #app { display: flex; align-items: center; justify-content: center; } .panel { padding: 20px; box-shadow: inherit; border-radius: 6px; box-shadow: 0 0 4px 0 #999999; margin-top: 100px; } </style> <div id="app"> <div class="panel"> <lazy-slide-captcha ref="captcha" :width="width" :height="height" :show-refresh="true" :fail-tip="failTip" :success-tip="successTip" @@finish="handleFinish" @@refresh="generate"></lazy-slide-captcha> </div> </div> @section Scripts{ <script src="~/lib/vue/vue.min.js"></script> <script src="~/lib/vue/axios.min.js"></script> <script src="~/lib/lazy-slide-captcha/dist/lazy-slide-captcha.umd.js"></script> <script> var app = new Vue({ el: '#app', data(){ return { requestId: undefined, failTip: '', successTip: '', // width,height保持与552 * 344同比例即可 width: 340, height: 212 } }, mounted(){ this.generate() }, methods:{ generate(){ // 改变内部状态,标识生成请求开始 this.$refs.captcha.startRequestGenerate() axios.get('/api/captcha/gen') .then((response) => { this.requestId = response.data.id // 改变内部状态,标识生成请求结束,同时设定background,slider图像 this.$refs.captcha.endRequestGenerate(response.data.backgroundImage, response.data.sliderImage) }) .catch((error) => { console.log(error); // 标识生成请求结束 this.$refs.captcha.endRequestGenerate(null, null) }); }, handleFinish(data){ // 改变内部状态,标识验证请求开始 this.$refs.captcha.startRequestVerify() axios.post(`/api/captcha/check?id=${this.requestId}`, data) .then((response) => { let success = response.data.result === 0 // 验证失败时显示信息 this.failTip = response.data.result == 1 ? '验证未通过,拖动滑块将悬浮图像正确合并' : '验证超时, 请重新操作' // 验证通过时显示信息 this.successTip = '验证通过,超过80%用户' // 改变内部状态,标识验证请求结束,同时设定是否成功状态 this.$refs.captcha.endRequestVerify(success) if(!success){ setTimeout(() => { this.generate() }, 1000) } }) .catch((error) => { console.log(error); this.failTip = '服务异常,请稍后重试' // 标识验证请求结束 this.$refs.captcha.endRequestVerify(false) }); } } }); </script> }折叠
至此,一个完整的滑动验证已实现,开启服务体验吧。
支持配置文件和代码配置,同时配置则代码配置覆盖配置文件。
"SlideCaptcha": { "ExpirySeconds": 60, // 缓存过期时长 "StoreageKeyPrefix": "", // 缓存前缀 "Tolerant": 0.02, // 容错值(校验时用,缺口位置与实际滑动位置匹配容错范围) "Backgrounds": [ // 背景图配置 { "Type": "file", "Data": "wwwroot/images/background/1.jpg" } ], // Templates不配置,则使用默认模板 "Templates": [ { "Slider": { "Type": "file", "Data": "wwwroot/images/template/1/slider.png" }, "Hole": { "Type": "file", "Data": "wwwroot/images/template/1/hole.png" } } ] }
builder.Services.AddSlideCaptcha(builder.Configuration, options => { options.Tolerant = 0.02f; options.StoreageKeyPrefix = "slider-captcha"; options.Backgrounds.Add(new Resource(FileResourceHandler.TYPE, @"wwwroot/images/background/1.jpg")); options.Templates.Add ( TemplatePair.Create ( new Resource(FileResourceHandler.TYPE, @"wwwroot/images/template/1/slider.png"), new Resource(FileResourceHandler.TYPE, @"wwwroot/images/template/1/hole.png") ) ); });
slider | hole | slider | hole |
---|---|---|---|
禁用默认 _Template_调用DisableDefaultTemplates即可:
builder.Services.AddSlideCaptcha(builder.Configuration) .DisableDefaultTemplates();
举一个栗子:
public class CustomValidator: BaseValidator { public override bool ValidateCore(SlideTrack slideTrack, CaptchaValidateData captchaValidateData) { // BaseValidator已做了基本滑块与凹槽的对齐验证,这里做其他验证 return true; } }
替换默认的Validator
builder.Services.AddSlideCaptcha(builder.Configuration); .ReplaceValidator<CustomValidator>();
public class CustomResourceProvider : IResourceProvider { public List<Resource> Backgrounds() { return Enumerable.Range(1, 10) .ToList() .Select(e => new Resource(Core.Resources.Handler.FileResourceHandler.TYPE, $"wwwroot/images/background/{e}.jpg")) .ToList(); } // 这里返回自定义的Template public List<TemplatePair> Templates() { return new List<TemplatePair>(); } }
注册ResourceProvider
builder.Services.AddSlideCaptcha(builder.Configuration) .AddResourceProvider<CustomResourceProvider>();
public class UrlResourceHandler : IResourceHandler { public const string Type = "url"; public bool CanHandle(string handlerType) { return handlerType == Type; } /// <summary> /// 这里仅演示,仍然从本地读取。实际需要通过Http读取 /// </summary> /// <param name="resource"></param> /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> public byte[] Handle(Resource resource) { if (resource == null) throw new ArgumentNullException(nameof(resource)); return File.ReadAllBytes(resource.Data); } }
注册ResourceHandler
builder.Services.AddSlideCaptcha(builder.Configuration) .AddResourceHandler<UrlResourceHandler>();
项目参考了tianai-captcha,vue-drag-verify非常优秀的项目,非常感谢。