Captcha MVC 是一个开源的ASP.NET MVC验证码库,首先我先上两张图,比较明白:
MathCaptchaMvc
PlainCaptchaMvc

第一张为数学验证码,第二张是文本验证码,包括样式效果是不是很漂亮。

一、安装

一方面可以通过官网(见参考资料),另一方面可以通过NuGet关键词Captcha MVC直接安装,分别有MVC3/4/5三个版本。

二、使用

在View所在页需要先引入命令空间 @using CaptchaMvc.HtmlHelpers。 这样我们可以通过HTML扩展方法直接创建数学或文本验证码。

不管是哪一个扩展方法,都带有 params ParameterModel[],通过他可以完成做任意验证码。

ParameterModel参数

  • InputTextAttribute 比如图片中的:Enter the result you see above,String类型。
  • RefreshTextAttribute 比如图片中的:Try another,String类型。
  • IsRequiredAttribute 是否为必填项,bool类型。
  • RequiredMessageAttribute 必填项提醒文本。
  • LengthAttribute 文本有效,字符长度,int类型。
  • ErrorAttribute 验证失败时提醒文本,默认:The captcha is not valid。
  • PartialViewNameAttribute 自定义布局的部分视图名称。
  • PartialViewDataAttribute 自定义布局的部分视图的ViewData参数。
  • ScriptPartialViewNameAttribute 自定义布局的部分视图的Script节点名称。

扩展方法

扩展方法实际是对默认属性值的一个初始化,虽然分别有 Html.CaptchaHtml.MathCaptcha 两种验证类型的扩展方法,但实际都是由上列属性表组合而来。

比如我们创建一个数字验证码,可以这样子:

@{
    CaptchaMvc.Models.ParameterModel[] catchaParams = new CaptchaMvc.Models.ParameterModel[] { 
        new CaptchaMvc.Models.ParameterModel(CaptchaMvc.Infrastructure.DefaultCaptchaManager.MathCaptchaAttribute, true),
        new CaptchaMvc.Models.ParameterModel(CaptchaMvc.Infrastructure.DefaultCaptchaManager.PartialViewNameAttribute, "_Captcha"),
        new CaptchaMvc.Models.ParameterModel(CaptchaMvc.Infrastructure.DefaultCaptchaManager.RefreshTextAttribute, "刷新文本"),
        new CaptchaMvc.Models.ParameterModel(CaptchaMvc.Infrastructure.DefaultCaptchaManager.IsRequiredAttribute, true),
        new CaptchaMvc.Models.ParameterModel(CaptchaMvc.Infrastructure.DefaultCaptchaManager.RequiredMessageAttribute, "必填项提醒文本")
    };
}
@Html.Captcha(6, catchaParams)

检查验证码是否有效

有两种方式可以验证。

使用属性:

        [CaptchaMvc.Attributes.CaptchaVerify("Captcha is not valid")]
        [HttpPost]
        public ActionResult MathCaptcha(string empty)
        {
            if (ModelState.IsValid)
            {
                TempData["Message"] = "Message: captcha is valid.";
                return View();
            }

            TempData["ErrorMessage"] = "Error: captcha is not valid.";
            return View();
        }

使用扩展方法:

        [HttpPost]
        public ActionResult Index(string empty)
        {
            if (this.IsCaptchaValid("Captcha is not valid"))
            {
                TempData["Message"] = "Message: captcha is valid.";
                return View();
            }

            TempData["ErrorMessage"] = "Error: captcha is not valid.";
            return View();
        }

三、自定义布局

在说这个之前得先了解一下大概的原理。所先当调用 Html.Captcha 后会产生一个 Token,对于刷新时需要一并提交 Token,否则只会返回一个黑框的图片。明白这一点后,以下是官网示例看起来会变得很容易懂,而且对于自定义布局来满足我们页面需求非常重要。

自定义文本验证码布局

@model CaptchaMvc.Models.DefaultBuildInfoModel
<img id="@Model.ImageElementId" src="@Model.ImageUrl" />
@Html.Hidden(Model.TokenElementId, Model.TokenValue)
<br />
@{
    string id = Guid.NewGuid().ToString("N");
    string functionName = string.Format("______{0}________()", Guid.NewGuid().ToString("N"));
    <script type="text/javascript">

        $(function () {
            $('#@id').show();
    });


    function @functionName {
            $('#@id').hide();
        $.post("@Model.RefreshUrl", { @Model.TokenParameterName: $('#@Model.TokenElementId').val() }, 
            function () {
                $('#@id').show();
            });
        return false;
    }
    </script>

    <a href="#@Model.InputElementId" id="@id" onclick="@functionName" style="display: none;">@Model.RefreshButtonText</a> 
}

<br />
@Model.InputText
<br />
@if (Model.IsRequired)
{
    @Html.TextBox(Model.InputElementId, null, new Dictionary<string, object>
                                                  {
                                                      {"data-val", "true"},
                                                      {"data-val-required", Model.RequiredMessage}
                                                  })
}
else
{
    @Html.TextBox(Model.InputElementId)
}
@Html.ValidationMessage(Model.InputElementId)

自定义数学验证码布局

@model CaptchaMvc.Models.MathBuildInfoModel

<img id="@Model.ImageElementId" src="@Model.ImageUrl" />
@Html.Hidden(Model.TokenElementId, Model.TokenValue)
<br />
@{
    string id = Guid.NewGuid().ToString("N");
    string functionName = string.Format("______{0}________()", Guid.NewGuid().ToString("N"));
   <script type="text/javascript">

    $(function () {
        $('#@id').show();
    });


    function @functionName {
        $('#@id').hide();
        $.post("@Model.RefreshUrl", { @Model.TokenParameterName: $('#@Model.TokenElementId').val(), 
@Model.MathParamterName: "0" }, 
            function () {  $('#@id').show();
        });
        return false;
    }
</script>

<a href="#@Model.InputElementId" id="@id" onclick="@functionName" style="display: none;">@Model.RefreshButtonText</a> 
}

<br />
@Model.InputText
<br />
@if (Model.IsRequired)
{
    @Html.TextBox(Model.InputElementId, null, new Dictionary<string, object>
                                                  {
                                                      { "data-val", "true" }, 
                                                      { "data-val-required", Model.RequiredMessage }
                                                  })
}
else
{
    @Html.TextBox(Model.InputElementId)   
}
@Html.ValidationMessage(Model.InputElementId)

这里还要注意的是,对于不同的验证码的 @model 也是不同。

四、Ajax问题

由于每一次验证的token都会不一样,所以如果form是ajax发送请求的话,那么我们还需要将在验证失败后,重新生成一个token,并将结果返回到客户端。这并不复杂,我们只需要调用 CaptchaHelper.GenerateCaptchaValue 来获取 IUpdateInfoModel 对象,这里面就有几个属性,其中 TokenElementIdTokenValue 就是新生成的 token。

var buildInfo = CaptchaMvc.HtmlHelpers.CaptchaHelper.GenerateCaptchaValue(controller, 6, GetParams());
return new
{
    TokenElementId = buildInfo.TokenElementId,
    TokenValue = buildInfo.TokenValue
};

这里的 GetParams() 是我自己封装的参数集合,上面已经很详细说明了。

参考资料