一步一步实现MVC5+EF6+Bootstarp+Autofac+NoSql实现OADemo 之登陆(一) 验证码 Captcha 之大插件小用

不知何年何月才能完成OADemo啊,总之还是一步一步来吧,这段时间开始着手了,先做登陆。  前段时间研究了一下在CentOS7下安装Mysql和Memcached服务,并测试了用C#操作,结果还行。

今天做一个简单的基于Bootstarp的响应式登陆页面(其实是在网上下的模板),不管是登陆还是注册吧,都会用到验证码,以前是用GDI绘出来的,觉得太丑了,百度的关于.net的验证码绝大多数也是用的这种方法,最后试了一下captcha,觉得还挺好看的,所以就试着用用。

nugit控制台install-package captcha到项目就行了,下载好了有个readme.txt文件,照着搞了一下,挺方便的

后台代码这样写的

[HttpPost]
        [CaptchaValidation("CaCode", "ExampleCaptcha", "Incorrect CAPTCHA code!")]
        public ActionResult ExampleAction(bool captchaValid)
        {

            if (!captchaValid)
            {
                return Content("no");
            }
            else
            {
                return Content("ok");
            }
        }

前台这样子的

<form action="/Example/ExampleAction" method="post">
        @{
            MvcCaptcha exampleCaptcha = new MvcCaptcha("ExampleCaptcha");
            exampleCaptcha.UserInputID = "CaCode";
            exampleCaptcha.ImageStyle = BotDetect.ImageStyle.CaughtInTheNet2;
            @Html.Captcha(exampleCaptcha)
            @*@Html.TextBox("CaCode")*@
            <input type="text" id="CaCode" name="CaCode"/>
                   }
            <input type="submit"  value="GO" />
        </form>

这都是照着readme搞的,当然还有注册路由的

public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.IgnoreRoute("{*botdetect}", new { botdetect = @"(.*)BotDetectCaptcha\.ashx" });
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }

就这三步就行了,然后测试一下,先输个错的试试,点GO,输出no,很好,再搞个对的,输出ok相当可以,再然后,不小心输错了还是ok,再然后空的还是ok???

把浏览器关了,重新生成再打开试,哪怕第一次是错的也是输出ok。另外还有一个问题点图片就会转到https://captcha.org/captcha.html?asp.net这个地址。

问题一

出现这个问题按理说应该是好事,说明插件帮我们做了缓存验证码的事,并且还设置了过期时间,将部分属性打印到页面看看情况

<form action="/Example/ExampleAction" method="post">
        @{
            MvcCaptcha exampleCaptcha = new MvcCaptcha("ExampleCaptcha");
            exampleCaptcha.UserInputID = "CaCode";
            exampleCaptcha.ImageStyle = BotDetect.ImageStyle.CaughtInTheNet2;
            @Html.Captcha(exampleCaptcha)
            @*@Html.TextBox("CaCode")*@
            <input type="text" id="CaCode" name="CaCode"/>
            <ul>
                <li>HelpLinkUrl:  @exampleCaptcha.HelpLinkUrl</li>
                <li>AddInitScript: @exampleCaptcha.AddInitScript</li>
                <li>AdditionalCssClasses: @exampleCaptcha.AdditionalCssClasses</li>
                <li>AdditionalInlineCss: @exampleCaptcha.AdditionalInlineCss</li>
                <li>AddScriptInclude: @exampleCaptcha.AddScriptInclude</li>
                <li>AutoClearInput: @exampleCaptcha.AutoClearInput</li>
                <li>AutoFocusInput: @exampleCaptcha.AutoFocusInput</li>
                <li>AutoReloadTimeout: @exampleCaptcha.AutoReloadTimeout</li>
                <li>CodeLength: @exampleCaptcha.CodeLength</li>
                <li>CodeStyle: @exampleCaptcha.CodeStyle</li>
                <li>CodeTimeout: @exampleCaptcha.CodeTimeout</li>
                <li>HelpLinkEnabled: @exampleCaptcha.HelpLinkEnabled</li>
                <li>HelpLinkText: @exampleCaptcha.HelpLinkText</li>
                <li>IconsDivWidth: @exampleCaptcha.IconsDivWidth</li>
                <li>ReloadIconUrl: @exampleCaptcha.ReloadIconUrl</li>
                <li>SoundIconUrl: @exampleCaptcha.SoundIconUrl</li>
                <li>ImageStyle: @exampleCaptcha.ImageStyle</li>
                <li>Locale: @exampleCaptcha.Locale</li>
                <li> @exampleCaptcha.HelpLinkMode</li>
                <li> @exampleCaptcha.WebCaptcha.CaptchaImageUrl</li>
                <li> @exampleCaptcha.WebCaptcha.CaptchaBase.GetCode("ExampleCaptcha", BotDetect.CodeGenerationPurpose.ImageGeneration).CaptchaCode</li>
            </ul>
        }
            <input type="submit"  value="GO" />
        </form>

从第一个属性来看应该是解决问题二的办法,但是很不幸,设置exampleCaptcha.HelpLinkUrl和HelpLinkText的值无效,结果还是回到了默认值。

还有就是CodeTimeout也是设置无效。在webconfig中

<sessionState mode="InProc" cookieless="AutoDetect" timeout="20" sessionIDManagerType="BotDetect.Web.CustomSessionIdManager, BotDetect" />

设置timeout小于20的值也无效,可能是有个最小值限定吧,这里我还没有试过超过20的值,晕!

其它的还好吧。

最后一个属性是我企图找出当前的验证码,依然很不幸,并不是,到现在我还没办法得到。之所以想得当验证码,其一是我觉得它帮我做的就是在session中缓存了验证码,可我并不想用session,如果只是保存在cookie中,那敢情好,我也无需得到验证码。

看看点击刷新按钮的请求

可以看出有三个GET请求,前两个是请求刷新和声音的按钮,后面一个是请求图片的。主要看后面一个,看来是有请求cookie的,并且有两个key。虽然如此,可我还并不肯定到底有没有用session缓存,关于这个,希望路过的大牛给予指导

再看看参数,有四个参数,每次请求只有d的值是变化的,这就是跟我们以前用的验证码刷新是一个意思啦。这个请求地址正是exampleCaptcha.WebCaptcha.CaptchaImageUrl的属性值。

看看刷新按钮最终生成的html是什么样子的,如下图,最关键的是a标签的onclick(红框框起部分),虽然看不到具体方法,但能知道方法的最终结果就是为了完成上面的请求。能理解这个,其它的都可以理解了。

其二我并不喜欢在前端写过多的C#代码。观察了一下后端代码

[CaptchaValidation("CaCode", "ExampleCaptcha", "Incorrect CAPTCHA code!")]

public ActionResult ExampleAction(bool captchaValid)...

对于Action的参数captchaValid我很不解,当我改变参数名称后就会报错,想想应该是CaptchaValidationAttribute中得来的吧,觉得用这个Attribute限制太多,不够灵活。最终我去掉了Attribute,用MvcCaptcha类的静态方法 MvcCaptcha.Validate(string,string,string),这个重载需要三个参数一个是captcha的Id,一个是用户输入值,另一个是validtingInstanceId

对于最后一个参数我开始摸不着北,后面在html源码中找到个hidden的input,只是感觉像是它,因为它有name属性,凭着感觉试了,没想还真行

那么就把后台给改了试试,其实最后个参数的值就是exampleCaptcha.CurrentInstanceId这个属性值(有时我自己觉得我有点傻的可爱),这样一来问题一就解决了部分问题,可以不用在前端写那么多C#代码了,并且每次登陆页面都要输入对的验证码才能ok。

public ActionResult ExampleAction(string CaCode, string BDC_VCID_ExampleCaptcha)
        {
            string instaneId = CustomCaptcha.CurrentInstanceId;
            bool captchaValid= MvcCaptcha.Validate("ExampleCaptcha", CaCode,BDC_VCID_ExampleCaptcha);
            if (captchaValid)
                return Content("ok");
            return Content("no");
        }

问题二

解决问题二我用的办法很粗暴,我后来重做了一个MVC项目,做了一个完整的登陆页面,那个刷新和声音按钮我不好布局,直接给隐藏了,既然它粗暴的让改属性值不能改变验证图片的点击链接,我又不能说让用户点图片进入一个外国网站,那么我也只能粗暴通过jquery来解决问题,我想的办法就是把前面关于刷新按钮的a标签的onclick给图片中a标签的onclick,简单粗暴。

虽然两个问题并没有完美解决,但感觉自己还在挺努力的。所以最后把修改的全部代码贴上吧

最终效果

前端

@{
    Layout = null;
}
@using BotDetect.Web.Mvc;
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1.0" />
    <title>登录</title>

    <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
    <link href="~/Content/LoginStyle.css" rel="stylesheet" />
    <script src="~/scripts/jquery-1.9.1.min.js"></script>
    <script src="~/scripts/bootstrap.min.js"></script>

    <script type="text/javascript">
        $(function () {
            $("#ExampleCaptcha_CaptchaImageDiv a").attr("onclick", "ExampleCaptcha.ReloadImage(); this.blur(); return false;")
            .attr("href", "#").attr("title", "点击刷新验证码");
        })
    </script>

</head>

<body>
    <div class="box">
        <div class="login-box">
            <div class="login-title text-center">
                <h1><small>登录</small></h1>
            </div>
            <div class="login-content ">
                <div class="form form-horizontal" >
                    <form action="/Login/Account" method="post">
                        <div class="form-group">
                            <div class="col-xs-12  ">
                                <div class="input-group">
                                    <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
                                    <input type="text" id="username" name="username" class="form-control" placeholder="用户名">
                                </div>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="col-xs-12  ">
                                <div class="input-group">
                                    <span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
                                    <input type="text" id="password" name="password" class="form-control" placeholder="密码">
                                </div>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="col-xs-12">
                                <div class="input-group">
                                    <div class="col-xs-6" style="margin-left:0" >
                                        <input type="text" id="CaptchaCode" style="width:200px" class="form-control"
                                               placeholder="输入验证码(点图可刷新)" name="CaptchaCode"/>
                                    </div>
                                    <div class="col-xs-6" style="margin-left:0">
                                        @Html.Captcha(CustomCaptcha.GetCaptcha("ExampleCaptcha",230,40,5))
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="form-group form-actions">
                            <div class="col-xs-4 col-xs-offset-4 ">
                                <button type="submit" class="btn btn-sm btn-info"><span class="glyphicon glyphicon-off"></span> 登录</button>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="col-xs-6 link">
                                <p class="text-center remove-margin">
                                    <small>忘记密码?</small> <a href="javascript:void(0)"><small>找回</small></a>
                                </p>
                            </div>
                            <div class="col-xs-6 link">
                                <p class="text-center remove-margin">
                                    <small>还没注册?</small> <a href="javascript:void(0)"><small>注册</small></a>
                                </p>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>

</body>

</html>

后端专门写了一个类,有一个静态属性,用于指定当前验证码的实例Id,一个静态方法,用于自定义captcha

using BotDetect.Web.Mvc;

namespace OADemo.MVCApp
{
    public class CustomCaptcha
    {
        /// <summary>
        /// 当前验证码的实例Id
        /// </summary>
        public static string CurrentInstanceId { get { return currentInstanceId; } }
        private static string currentInstanceId;
        public static MvcCaptcha GetCaptcha(string captchaId)
        {
            MvcCaptcha exampleCaptcha = new MvcCaptcha(captchaId);
            exampleCaptcha.ImageStyle = BotDetect.ImageStyle.CaughtInTheNet2;
            exampleCaptcha.ReloadEnabled = false;
            exampleCaptcha.SoundEnabled = false;
            currentInstanceId = exampleCaptcha.CurrentInstanceId;
            return exampleCaptcha;
        }
        /// <summary>
        /// 获取自定义的验证码样式
        /// </summary>
        /// <param name="captchaId"></param>
        /// <param name="width">指定验证码图片的宽度</param>
        /// <param name="height">指定验证码图片的高度</param>
        /// <param name="codeLength">指定验证码的个数</param>
        /// <returns></returns>
        public static MvcCaptcha GetCaptcha(string captchaId,int width,int height,int codeLength)
        {
            MvcCaptcha exampleCaptcha = new MvcCaptcha(captchaId);
            exampleCaptcha.ImageStyle = BotDetect.ImageStyle.CaughtInTheNet2;//我个人喜欢的风格
            exampleCaptcha.ReloadEnabled = false;//去掉刷新的按钮
            exampleCaptcha.SoundEnabled = false;//去掉声音播放按钮
            exampleCaptcha.CodeLength = codeLength;//指定验证码的长度
            exampleCaptcha.ImageSize = new System.Drawing.Size(width,height);//指定图片的大小
            currentInstanceId = exampleCaptcha.CurrentInstanceId;//当前实例的id
            return exampleCaptcha;
        }
    }
}

后端控制器代码

using System.Web.Mvc;

namespace OADemo.MVCApp.Controllers
{
    public class LoginController : Controller
    {

        // GET: Login
        public ActionResult Index()
        {
            return View();
        }
        public ActionResult Account(string CaptchaCode, string name, string pwd,string BDC_VCID_ExampleCaptcha)
        {
            string instaneId = CustomCaptcha.CurrentInstanceId;
            bool captchaValid= MvcCaptcha.Validate("ExampleCaptcha", CaptchaCode,instaneId);
            if (captchaValid)
                return Content("ok");
            return Content("no");
        }
    }
}

Controller Code

好吧,后端控制器代码应该是这样才对的

using System.Web.Mvc;

namespace OADemo.MVCApp.Controllers
{
    public class LoginController : Controller
    {

        // GET: Login
        public ActionResult Index()
        {
            return View();
        }
        public ActionResult Account(string CaptchaCode, string username, string password)
        {
            string instaneId = CustomCaptcha.CurrentInstanceId;
            bool captchaValid= MvcCaptcha.Validate("ExampleCaptcha", CaptchaCode,instaneId);
            if (captchaValid)
                return Content("ok");
            return Content("no");
        }
    }
}

目前就写到这里了,当然后面的验证还没写,还只是在测试captcha阶段,所以想说要源码的同志,就不要费力了,因为这里忘记密码和注册都没有写的。这一篇完全只是写的我目前对captcha的研究,也许在众多的MvcCaptcha类的事件中,才是真正有效解决问题的办法,只是我没有英文水平,加上现在时间太晚,眼睛和脑袋受不了,暂告一段落,事件这么多呢,搞懂了,webconfig配置都可以自定义

 public static event EventHandler<GeneratedCaptchaCodeEventArgs> GeneratedCaptchaCode;
        public static event EventHandler<GeneratedCaptchaImageEventArgs> GeneratedCaptchaImage;
        public static event EventHandler<GeneratedCaptchaSoundEventArgs> GeneratedCaptchaSound;
        public static event EventHandler<GeneratingCaptchaCodeEventArgs> GeneratingCaptchaCode;
        public static event EventHandler<GeneratingCaptchaImageEventArgs> GeneratingCaptchaImage;
        public static event EventHandler<GeneratingCaptchaSoundEventArgs> GeneratingCaptchaSound;
        public static event EventHandler<InitializedWebCaptchaEventArgs> InitializedWebCaptcha;
        public static event EventHandler<ValidatedUserInputEventArgs> ValidatedUserInput;
        public static event EventHandler<ValidatingUserInputEventArgs> ValidatingUserInput;
时间: 2024-10-10 14:54:09

一步一步实现MVC5+EF6+Bootstarp+Autofac+NoSql实现OADemo 之登陆(一) 验证码 Captcha 之大插件小用的相关文章

MVC5+EF6+Bootstarp+Autofac+NoSql实现OADemo 之登陆(一) 验证码 Captcha 之大插件小用

不知何年何月才能完成OADemo啊,总之还是一步一步来吧,这段时间开始着手了,先做登陆. 前段时间研究了一下在CentOS7下安装Mysql和Memcached服务,并测试了用C#操作,结果还行. 今天做一个简单的基于Bootstarp的响应式登陆页面(其实是在网上下的模板),不管是登陆还是注册吧, ... bbs.chinaacc.com/forum-2-3/topic-5655867.html bbs.chinaacc.com/forum-2-3/topic-5655895.html bbs

一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](十一)

前言 小伙伴们,大家好,我是Rector.最近Rector忙于换工作,没有太多时间来更新我们的ASP.NET MVC 5系列文章 [一步一步创建ASP.NET MVC5程序Repository+Autofac+Automapper+SqlSugar],直到现在才挤些时间赶紧更新一篇,小伙伴们等得太久了. 写系列文章是一件并不容易的事情,相信有过写系列文章经验朋友也应该有所体会. 本文知识要点 本期是该系列的第十一篇,上一篇<一步一步创建ASP.NET MVC5程序[Repository+Auto

MVC5+EF6 入门完整教程九

前一阵子临时有事,这篇文章发布间隔比较长,我们先回顾下之前的内容,每篇文章用一句话总结重点. 文章一 MVC核心概念简介,一个基本MVC项目结构 文章二 通过开发一个最基本的登录界面,介绍了如何从Controller中获取表单数据 文章三 EF的整个开发过程 文章四 EF基本的CRUD和常用的HtmlHelper 文章五 使用布局页(模板页)改造UI 文章六 分部视图(Partial View) 文章七 排序过滤分页 文章八 不丢失数据进行数据库结构升级 以上如果有不清楚的可以再回去看一下. 文

MVC5+EF6 简易版CMS(非接口) 第三章:数据存储和业务处理

目录 简易版CMS后台管理系统开发流程 MVC5+EF6 简易版CMS(非接口) 第一章:新建项目 MVC5+EF6 简易版CMS(非接口) 第二章:建数据模型 MVC5+EF6 简易版CMS(非接口) 第三章:数据存储和业务处理 MVC5+EF6 简易版CMS(非接口) 第四章:使用业务层方法,以及关联表解决方案 先来了解下各项的引用关系 FytCms.DALMSSQL=>Domain.Entity.EntityFramework BusinessLogic.Server=>FytCms.D

下页小希学MVC5+EF6.2 学习记录一

目的:1 学习mvc+ef 2  写下日记也是对自己的督促 第0课 从0开始 ASP.NET MVC开发模式和传统的WebForm开发模式相比,增加了很多"约定". 直接讲这些 "约定" 会让人困惑,而且东西太多容易忘记. 和微软官方教程不同,笔者尽量不用脚手架,从空白框架开始,一步一步添加功能,每次添加的东西刚好够用,让大家能真正能用起来,理解每一个过程. 文章提纲 概述 核心概念介绍 从空白开始,建立一个基本框架详细步骤 概述 本系列文章及文章中的例子主要基于微

ASP.NET MVC5+EF6+EasyUI 后台管理系统-关于WebApi的用法

1:ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-WebApi与Unity注入 使用Unity是为了使用我们后台的BLL和DAL层 2:ASP.NET MVC5+EF6+EasyUI 后台管理系统(2)-WebApi与Unity注入-配置文件 3:ASP.NET MVC5+EF6+EasyUI 后台管理系统(3)-MVC WebApi 用户验证 (1) 4:ASP.NET MVC5+EF6+EasyUI 后台管理系统(4)-MVC WebApi 用户验证 (2) 以往我们讲

一步一步学习SignalR进行实时通信_1_简单介绍

原文:一步一步学习SignalR进行实时通信_1_简单介绍 一步一步学习SignalR进行实时通信\_1_简单介绍 SignalR 一步一步学习SignalR进行实时通信_1_简单介绍 前言 SignalR介绍 支持的平台 相关说明 OWIN 结束语 参考文献 前言 本来前几个月想写一系列的关于SignalR的文章,但是由于在做项目,时间非常的紧急,花了1天的时间大致了解了下SignalR,并实现了个在线聊天的小功能,本来记录一系列关于SignalR的文章,没想到写了MVC5使用SignalR进

一步一步学习SignalR进行实时通信_2_Persistent Connections

原文:一步一步学习SignalR进行实时通信_2_Persistent Connections 一步一步学习SignalR进行实时通信\_2_Persistent Connections SignalR 一步一步学习SignalR进行实时通信_2_Persistent Connections 前言 安装 Persistent Connections 映射并配置持久连接 结束语 参考文献 前言 上一篇文章简单的介绍了下SignalR,从此篇文章就开始对SignalR进行剖析.在介绍Persiste

一步一步学习Vue(十一)

本篇继续学习vuex,还是以实例为主:我们以一步一步学Vue(四)中讲述的例子为基础,对其改造,基于vuex重构一遍,这是原始的代码: todolist.js ; (function () { var list = []; var Todo = (function () { var id = 1; return function (title, desc) { this.title = title; this.desc = desc; this.id = id++; } })(); /** *