议题
很多自动程序会自动提交表单,在互联网上造成大量的垃圾数据,为了防止这种情况发生,我们实现了图形验证码(CAPTCHA:Completely Automated Public Turing test to tell Computers and Humans Apart),当用户提交时必须要在文本框中输入图片上显示的正确的字符。
解决方案
在BookCommentsControllor控制器中安装ASP.NET Web Helper Library中NuGet提供的CAPTCHA。
讨论
包含一个新的Library Package,在窗体上添加一个CAPTCHA。Microsoft在NuGet Web Helpers Library中内置CAPTCHA类,可以让我们很容易的实现验证用户输入的CAPTCHA。
在Visual Studio的MVC应用程序项目中,点击菜单“工具”→“Library Package Manager”→“Add Library Package Reference”。载入后,在左侧选择“Online”分类,在首页中选择“microsoft-web-helpers”,如果它不在列表里面,请在右上角搜索。找到后,点击“Install”。
最典型的提交表单的案例就是提交评论。在之前的配方中,添加书籍评论就是添加CAPTCHA的完美事例。在开始之前,你需要将域名注册到RECAPTCHA网站。完成注册后,将会收到你网站专用的私钥和公钥。将它们复制保存以备将来使用。
设置完成后,开始修改代码。在BookComments/Index视图中做一个小修改即可。这是之前创建的添加评论的页面,在发起Ajax请求时,显示CAPTCHA按钮,并在请求完成时调用名为“DisplayCaptcha”的Javascript方法。
@model IEnumerable<MvcApplication4.Models.BookComment>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Ajax.ActionLink("Create New", "Create", new {
BookId = ViewBag.BookId },
new AjaxOptions { UpdateTargetId = "AddComment",
OnComplete = "DisplayCaptcha" })
</p>
<div id="AddComment"></div>
...
<script type="text/javascript" src=
"http://www.google.com/recaptcha/api/js/recaptcha_ajax.js">
</script>
<script type="text/javascript">
function DisplayCaptcha() {
Recaptcha.destroy();
Recaptcha.create("<your_public_key>", "captcha", {});
}
</script>
现在对BookComments/Create视图做一个小修改。首先,需要创建一个区域显示CAPTCHA和一个新的HTML标记,在用户输入错误的时候显示错误信息。最后,修改一下ReloadComment方法,在没有自动重新载入的情况下显示CAPTCHA(仅当没有出错时)。
@model MvcApplication4.Models.BookComment
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@section JavascriptAndCSS {
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")"
type="text/javascript"></script>
<script src="
@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"
type="text/javascript"></script>
}
<script type="text/javascript">
function ReloadComments() {
var reload = "@ViewBag.RefreshComments";
if (reload == "False") {
DisplayCaptcha();
} else {
$("#Comments").load(
"/BookComments/[email protected]");
}
}
</script>
@using (Ajax.BeginForm(new AjaxOptions {
UpdateTargetId="AddComment", OnComplete="ReloadComments" }))
{
@Html.Hidden("BookId", (int)ViewBag.BookId);
@Html.ValidationSummary(true)
<fieldset>
<legend>BookComment</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Comment)
</div>
<div class="editor-field">
@Html.TextAreaFor(model => model.Comment)
@Html.ValidationMessageFor(model => model.Comment)
</div>
<div class="editor-label">
Are you human?
</div>
<div class="editor-field">
<div id="captcha"></div>
@Html.ValidationMessage("Captcha")
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
最后,需要修改BookCommentsController验证用户输入的CAPTCHA。假如验证不成功,将错误信息添加到ModelState中,返回到视图中显示。
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication4.Models;
using Microsoft.Web.Helpers;
namespace MvcApplication4.Controllers
{
public class BookCommentsController : Controller
{
private BookDBContext db = new BookDBContext();
//
// GET: /BookComments/
public ActionResult Index(int BookId)
{
ViewBag.BookId = BookId;
var bookcomments = db.BookComments.Include(
b => b.Book).Where(b => b.BookId == BookId);
return PartialView(bookcomments.ToList());
}
//
// GET: /BookComments/Create
public ActionResult Create(int BookId)
{
ViewBag.BookId = BookId;
ViewBag.RefreshComments = false;
return PartialView();
}
//
// POST: /BookComments/Create
[HttpPost]
public ActionResult Create(BookComment bookcomment)
{
ViewBag.RefreshComments = false;
var captchaSuccess = ReCaptcha.Validate(
"<your_private_key>");
if (ModelState.IsValid && captchaSuccess)
{
bookcomment.Created = DateTime.Now;
db.BookComments.Add(bookcomment);
db.SaveChanges();
ViewBag.RefreshComments = true;
}
// if captcha failed add error message
if (!captchaSuccess)
{
ModelState.AddModelError("Captcha",
"Invalid CAPTCHA");
}
ViewBag.BookId = bookcomment.BookId;
return PartialView(bookcomment);
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
参考