Asp.net mvc 在服务器往返和随后重新生成验证码后验证验证码

Asp.net mvc 在服务器往返和随后重新生成验证码后验证验证码,asp.net-mvc,Asp.net Mvc,我正在根据Sanderson的书Pro ASP.NET MVC框架在表单提交中实现CAPTCHA 视图字段由以下内容生成: <%= Html.Captcha("testCaptcha")%> <%= Html.TextBox("attemptCaptcha")%> public static string Captcha(this HtmlHelper html, string name) { // Pick a GUID to represent this c

我正在根据Sanderson的书Pro ASP.NET MVC框架在表单提交中实现CAPTCHA

视图字段由以下内容生成:

<%= Html.Captcha("testCaptcha")%>
<%= Html.TextBox("attemptCaptcha")%>
public static string Captcha(this HtmlHelper html, string name)
{
    // Pick a GUID to represent this challenge
    string challengeGuid = Guid.NewGuid().ToString();
    // Generate and store a random solution text
    var session = html.ViewContext.HttpContext.Session;
    session[SessionKeyPrefix + challengeGuid] = MakeRandomSolution();

    // Render an <IMG> tag for the distorted text,
    // plus a hidden field to contain the challenge GUID
    var urlHelper = new UrlHelper(html.ViewContext.RequestContext);
    string url = urlHelper.Action("Render", "CaptchaImage", new{challengeGuid});
    return string.Format(ImgFormat, url) + html.Hidden(name, challengeGuid);
}
但是,这样做会生成一个新的GUID,该GUID会生成新的验证码文本

但是,问题是,验证码隐藏字段值和验证码图像url都保留原始GUID。因此,您永远无法输入正确的值。你基本上只有一次机会把它做好

我对所有这些都不熟悉,但这与视图保留第一页加载的值有关

验证码是通过以下方式生成的:

<%= Html.Captcha("testCaptcha")%>
<%= Html.TextBox("attemptCaptcha")%>
public static string Captcha(this HtmlHelper html, string name)
{
    // Pick a GUID to represent this challenge
    string challengeGuid = Guid.NewGuid().ToString();
    // Generate and store a random solution text
    var session = html.ViewContext.HttpContext.Session;
    session[SessionKeyPrefix + challengeGuid] = MakeRandomSolution();

    // Render an <IMG> tag for the distorted text,
    // plus a hidden field to contain the challenge GUID
    var urlHelper = new UrlHelper(html.ViewContext.RequestContext);
    string url = urlHelper.Action("Render", "CaptchaImage", new{challengeGuid});
    return string.Format(ImgFormat, url) + html.Hidden(name, challengeGuid);
}
用guid重新构建目标字段名怎么样?那么,每个字段都是唯一的,不会保留前几代表单的值吗


还是我只需要一个不同的验证码实现?

因此,我决定实现reCaptcha。我也定制了自己的观点:

<div id="recaptcha_image"></div>&nbsp;
     <a href="#" onclick="Recaptcha.reload();">
            generate a new image
     </a><br />
<input type="text" name="recaptcha_response_field" 
           id="recaptcha_response_field" />
           &nbsp;<%= Html.ValidationMessage("attemptCaptcha")%>
<script type="text/javascript" 
     src="http://api.recaptcha.net/challenge?k=[my public key]"></script>
所有这些都假设您已经实现了Action Filter属性和view helper,如recaptcha.net所述:

public class CaptchaValidatorAttribute : ActionFilterAttribute
{
    private const string CHALLENGE_FIELD_KEY = "recaptcha_challenge_field";
    private const string RESPONSE_FIELD_KEY = "recaptcha_response_field";

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var captchaChallengeValue = 
             filterContext.HttpContext.Request.Form[CHALLENGE_FIELD_KEY];
        var captchaResponseValue = 
             filterContext.HttpContext.Request.Form[RESPONSE_FIELD_KEY];
        var captchaValidtor = new Recaptcha.RecaptchaValidator
          {
              PrivateKey = "[my private key]",
              RemoteIP = filterContext.HttpContext.Request.UserHostAddress,
              Challenge = captchaChallengeValue,
              Response = captchaResponseValue
          };

        var recaptchaResponse = captchaValidtor.Validate();

    // this will push the result value into a parameter in our Action
        filterContext.ActionParameters["captchaValid"] = recaptchaResponse.IsValid;

        base.OnActionExecuting(filterContext);
    }
}
html帮助程序:

public static class Captcha
{
    public static string GenerateCaptcha( this HtmlHelper helper )
    {  
    var captchaControl = new Recaptcha.RecaptchaControl
        {
            ID = "recaptcha",
            Theme = "clean",
            PublicKey = "[my public key]",
            PrivateKey = "[ my private key ]"
        };
    var htmlWriter = new HtmlTextWriter( new StringWriter() );
        captchaControl.RenderControl(htmlWriter);
    return htmlWriter.InnerWriter.ToString();
    }
}

希望这能帮助那些被书中的实现困住的人。

我在使用Sanderson书中的captcha示例时也遇到了同样的问题。问题是,页面被浏览器缓存,在验证码测试失败后不会刷新。因此,它总是显示相同的图像,即使生成并存储了新的验证码以供测试

一种解决方案是在尝试失败后重新加载页面时强制浏览器刷新页面;如果只返回View(),则不会发生这种情况。您可以使用RedirectToAction(“SubmiteSay”)执行此操作,它将命中接受HttpVerbs.Get的操作方法

当然,您将无法使用ViewData通知用户错误,但您可以将其包含在查询字符串中,然后只检查查询字符串以显示消息

所以,以这本书为例

if (!CaptchaHelper.VerifyAndExpireSolution(HttpContext, captcha, captchaAttempt) 
{
    RedirectToAction("SubmitEssay", new { fail = 1 });
}

然后只需检查QueryString集合是否包含传递错误消息的“fail”。

唯一字段名不起作用。我也经历了同样的事情。目标字段只在第一次创建之后才被缓存,不再重新生成。这可能就是为什么像reCaptcha这样基于javascript的实现可能更好的原因。
public static class Captcha
{
    public static string GenerateCaptcha( this HtmlHelper helper )
    {  
    var captchaControl = new Recaptcha.RecaptchaControl
        {
            ID = "recaptcha",
            Theme = "clean",
            PublicKey = "[my public key]",
            PrivateKey = "[ my private key ]"
        };
    var htmlWriter = new HtmlTextWriter( new StringWriter() );
        captchaControl.RenderControl(htmlWriter);
    return htmlWriter.InnerWriter.ToString();
    }
}
if (!CaptchaHelper.VerifyAndExpireSolution(HttpContext, captcha, captchaAttempt) 
{
    RedirectToAction("SubmitEssay", new { fail = 1 });
}