簡單幾步實現滑動驗證碼(后端驗證)


LazySlideCaptcha

介紹

LazySlideCaptcha是基於.Net Standard 2.1的滑動驗證碼模塊。項目同時提供一個基於vue2的演示前端組件背景圖裁剪工具
【碼雲地址】 | 【Github 地址】

圖形驗證碼請移步lazy-captcha

在線體驗點這里

快速開始

  1. 安裝
Install-Package Lazy.SlideCaptcha.Core
dotnet add package Lazy.SlideCaptcha.Core
  1. 注冊並配置服務
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 bool 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非常優秀的項目,非常感謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM