[转载]ASP.NET MVC3 20个秘方-(15)使用CAPTCHA去防止恶意软件自动提交评论(防灌水)

[转载]【译】MVC3 20个秘方-(15)使用CAPTCHA去防止恶意软件自动提交评论(防灌水) – 技术弟弟 – 博客园.

问题

有种不太幸运的情况,有人用自动程序去提交表单,在整个互联网中造成大量的垃圾。为了防止这种情况的方法之一,是使用一个验证码—CAPTCHA:全自动区分计算机和人类的图灵测试,这迫使用户把生成的文字输入到文本框。

(译者:CAPTCHA是一种更人性化的验证码,可以通过视觉和听觉来区分post的请求是人类还是计算机发出的)

解决方案

NuGet安装ASP.NET Web Helpers Library 从而在BookCommentsController实现防止而已添加书评的功能。

讨论

需要安装一个新的类包,使在表单上应用CAPTCHA成为可能。微软已经创建了一个NuGet web helpers 类包含了CAPTCHA,让我们很容易实施并且验证用户输入的CAPTCHA。先打开MVC项目,在vs中选择Tools→LibraryPackage Manager→Add Library Package Reference。点击左边的Online,在第一页的下方您就可以发现 ASP.NET web helpers Library。点击安装。

在我们的例子里。那些自动发送post请求的软件一般会用在图书评论上。所以是这里最完美的添加CAPTCHA的地方。在开始之前你必须在RECAPTCHA website为你的域名注册。(译者:一般要用一个gmail账户。我们使用自己已有的或者重新注册一个,在这里由于我们的项目是在本机练习使用的,我就为我的localhost注册)。注册成功之后你可以得到一个公钥(public key)和一个私钥(private key)。

提示:如果你不使用Ajax去包含CAPTCHA,你可以通过以下两行代码改变你的view:

@using Microsoft.Web.Helpers;
@ReCaptcha.GetHtml("<你的公钥>", "<你的私钥>")

一旦配置完成了,是时候开始更新我们的代码了。我们需要在BookComments/Index view里做一些小更改。这个view是前一段创建的,用于使用ajax提交书评。这个Ajax需要更新成:当请求完毕,调用JavaScript函数去 显示CAPTCHA按钮。代码如下:

@model IEnumerable<MvcApplication.Models.BookComment>
@{
    ViewBag.Title = "Index";
}
<h2>
    Index</h2>
<p>
    @Ajax.ActionLink("Create New", "Create", new
{
    BookId = ViewBag.BookId
},
new AjaxOptions { UpdateTargetId = "AddComment" })
</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("6Le27coSAAAAAK8KqpUIGvz3qTDXGa9ud9Xst4yY", "captcha", {});//你的公钥

    }
</script>
<table>
    <tr>
        <th>
            Comment
        </th>
        <th>
            Created
        </th>
    </tr>
    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Comment)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Created)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Book.Title)
            </td>
        </tr>
    }
</table>

现在,去更新BookComments/create view 。首先添加一个地点去展示CAPTCHA.然后添加一个新的HTML 错误消息,当他们输入错误的验证码时,会提示错误。最后在ReloadComment  JavaScript 函数里更改代码成不自动reload 书评(仅仅当没错的时候才reload)。

@model MvcApplication.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/Index?BookId=@ViewBag.BookId");
        }
    }
</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里去,view把它展示出来。

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication.Models;
using Microsoft.Web.Helpers;
using MvcApplication.Models;
namespace MvcApplication.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(
            "6Le27coSAAAAAM6kZnXU8m1j9");//你的私钥

            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);
        }
    }
}

(译者:下图是我实践之后的截图,不知道这个CAPTCHA的背景样式是否能自定义,如果可以的话就太酷了!)

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏