5 Star 121 Fork 43

pojianbing / LazySlideCaptcha

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

LazySlideCaptcha (基于SkiaSharp)

介绍

LazySlideCaptcha是基于.Net Standard 2.1的滑动验证码模块。项目同时提供一个基于vue2的演示前端组件背景图裁剪工具。从2.0.0起绘图模块由ImageSharp调整为SkiaSharp。 【码云地址】|【Github地址】

图形验证码请移步lazy-captcha

在线体验点这里

输入图片说明

快速开始

  1. 安装
Install-Package Lazy.SlideCaptcha.Core
dotnet add package Lazy.SlideCaptcha.Core
  1. 注册并配置服务
builder.Services.AddDistributedMemoryCache();
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 图片。

  1. 接口定义
[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 ValidateResult Validate([FromQuery]string id, SlideTrack track)
    {
        return _captcha.Validate(id, track);
    }
}

至此后端Api服务已搭建完成。

  1. 前端
    前端提供演示组件lazy-slide-captcha,可通过npm安装。Demo项目为了演示方便直接采用script直接引入方式。
@{
    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")
        )
    );
});

扩展

  1. Template自定义
    Template 是指用于生成凹槽和拖块的图片,可通过Templates配置节点设置设置自定义Template。 默认五个 Template (不要配置,已经包含在类库内部)如下:
slider hole slider hole

禁用默认 _Template_调用DisableDefaultTemplates即可:

builder.Services.AddSlideCaptcha(builder.Configuration)
    .DisableDefaultTemplates();
  1. Validator自定义 类库提供 SimpleValidatorBasicValidator 两个实现。
    SimpleValidator 仅位置验证,BasicValidator除位置验证外,同时对轨迹做验证。BasicValidator由于算法的原因,容易误判,因此类库默认用SimpleValidator_ 做为默认 Validator
    自定义 Validator 继承 BaseValidatorBaseValidator 提供了基本的位置验证。

举一个栗子:

public class CustomValidator: BaseValidator
{
    public override bool ValidateCore(SlideTrack slideTrack, CaptchaValidateData captchaValidateData)
    {
        // BaseValidator已做了基本滑块与凹槽的对齐验证,这里做其他验证

        return true;
    }
}

替换默认的Validator

builder.Services.AddSlideCaptcha(builder.Configuration);
    .ReplaceValidator<CustomValidator>();
  1. ResourceProvider自定义
    除了通过Options配置Background和Template外,你也可以通过自定义ResourceProvider的形式提供Background和Template。
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>();
  1. 自定义ResourceHandler
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-captchavue-drag-verify非常优秀的项目,非常感谢。

MIT License Copyright (c) 2022 pojianbing Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

.net core滑动验证码 展开 收起
MIT
取消

发行版 (1)

全部

贡献者

全部

近期动态

加载更多
不能加载更多了
C#
1
https://gitee.com/pojianbing/lazy-slide-captcha.git
git@gitee.com:pojianbing/lazy-slide-captcha.git
pojianbing
lazy-slide-captcha
LazySlideCaptcha
master

搜索帮助