• (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:

    双击代码全选
    1
    2
    @using Microsoft.Web.Helpers;
    @ReCaptcha.GetHtml("<你的公钥>", "<你的私钥>")
     

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

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    @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=
    </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)。

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    @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把它展示出来。

    双击代码全选
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    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的背景样式是否能自定义,如果可以的话就太酷了!)

     
    年轻不是你玩的理由,而是你奋斗的资本
  • 相关阅读:
    多Web服务器之间共享Session的解决方案
    在WinForm中使用CacheDependency来监视文件
    使用WCF的一些问题
    IIS6.0配置注意
    匿名委托注册事件的触发
    关于datawindow does not have update capability
    EF自关联建模详解
    NHiberante3.2版注意
    EF做数据绑定时一些神奇问题
    EF 中不同会话上下文的对象,不能互设为对方的导航属性值
  • 原文地址:https://www.cnblogs.com/lyaxx1314/p/3603513.html
Copyright © 2020-2023  润新知