根据Sanderson的书籍 Pro ASP.NET MVC Framework ,我在表单提交中实现了CAPTCHA。
使用以下内容生成视图字段:
<%= Html.Captcha("testCaptcha")%>
<%= Html.TextBox("attemptCaptcha")%>
VerifyAndExpireSolution助手无法正常工作,因为他的解决方案已实施。
我正在添加验证,当它失败时,我会添加一个ModelState错误消息并将用户发送回视图中所述的视图:
return ModelState.IsValid ? View("Completed", appt) : View();
但是,这样做会生成一个新的GUID,用于生成新的CAPTCHA文本。
但问题是,CAPTCHA隐藏字段值和CAPTCHA图像网址都保留原始 GUID。所以,你永远无法输入正确的价值。你基本上只有一次机会才能做到正确。
我是所有这一切的新手,但它与保留第一页加载的值的视图有关。
使用以下代码生成验证码。
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);
}
然后我尝试用以下方法验证它:
public static bool VerifyAndExpireSolution(HttpContextBase context,
string challengeGuid,
string attemptedSolution)
{
// Immediately remove the solution from Session to prevent replay attacks
string solution = (string)context.Session[SessionKeyPrefix + challengeGuid];
context.Session.Remove(SessionKeyPrefix + challengeGuid);
return ((solution != null) && (attemptedSolution == solution));
}
如何使用guid重建目标字段名称?那么,每个字段都是唯一的,并且不会保留以前的表单代的值?
或者我只需要一个不同的CAPTCHA实现?
答案 0 :(得分:1)
我使用Sanderson的书中的验证码示例遇到了同样的问题。问题是页面被浏览器缓存,并且在验证码测试失败后不会刷新。因此它总是显示相同的图像,即使已经生成并存储了新的验证码以进行测试。
一种解决方案是在尝试失败后重新加载时强制浏览器刷新页面;如果你只返回View(),就不会发生这种情况。您可以使用RedirectToAction(“SubmitEssay”)执行此操作,该操作将触及接受HttpVerbs.Get的操作方法。
当然,您无法使用ViewData通知您的用户错误,但您可以将其包含在查询字符串中,然后只需检查查询字符串以显示您的消息。
所以,按照这本书的例子,
if (!CaptchaHelper.VerifyAndExpireSolution(HttpContext, captcha, captchaAttempt)
{
RedirectToAction("SubmitEssay", new { fail = 1 });
}
然后检查QueryString集合是否包含“fail”以传递错误消息。
答案 1 :(得分:0)
所以,我决定实施reCaptcha。我也同样定制了我的观点:
<div id="recaptcha_image"></div>
<a href="#" onclick="Recaptcha.reload();">
generate a new image
</a><br />
<input type="text" name="recaptcha_response_field"
id="recaptcha_response_field" />
<%= Html.ValidationMessage("attemptCaptcha")%>
<script type="text/javascript"
src="http://api.recaptcha.net/challenge?k=[my public key]"></script>
这会创建两个验证码 - 一个在我的图像容器中,另一个由脚本创建。所以,我添加了css来隐藏自动生成的:
<style type="text/css">
#recaptcha_widget_div {display:none;}
</style>
然后,在我的控制器中,我只需要测试captchaValid:
[CaptchaValidator]
[AcceptVerbs(HttpVerbs.Post)]
public ViewResult SubmitEssay(Essay essay, bool acceptsTerms, bool captchaValid)
{
if (!acceptsTerms)
ModelState.AddModelError("acceptsTerms",
"You must accept the terms and conditions.");
else
{
try
{
// save/validate the essay
var errors = essay.GetRuleViolations(captchaValid);
if (errors.Count > 0)
throw new RuleException(errors);
}
catch (RuleException ex)
{
ex.CopyToModelState(ModelState, "essay");
}
}
return ModelState.IsValid ? View("Completed", essay) : View();
}
public NameValueCollection GetRuleViolations(bool captchaValid)
{
var errors = new NameValueCollection();
if (!captchaValid)
errors.Add("attemptCaptcha",
"Please enter the correct verification text before submitting.");
// continue with other fields....
}
所有这些假设您已经实现了Action Filter属性和视图助手,详见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 helper:
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();
}
}
希望这可以帮助那些在书中坚持实施的人。