最近因为有个项目除了登录还有其他很多地方需要用到验证码的功能,所以想到了采用HtmlHelper和ActionFilter封装一个验证码的功能,以便能够重复调用。封装好以后调用很方便,只需在View中调用Html扩展好的方法,相应的Action加上验证功能的Filter就行了。

首先写一个能够随机生成数字的图片的类,园子里有一大把这样的文章,直接拿过来就用了,自己懒得写了。

   public class CaptchaRender
{
public CaptchaRender()
{
} /// <summary>
/// 验证码的最大长度
/// </summary>
public int MaxLength
{
get { return ; }
} /// <summary>
/// 验证码的最小长度
/// </summary>
public int MinLength
{
get { return ; }
} /// <summary>
/// 生成验证码
/// </summary>
/// <param name="length">指定验证码的长度</param>
/// <returns></returns>
public string CreateValidateCode(int length)
{
int[] randMembers = new int[length];
int[] validateNums = new int[length];
string validateNumberStr = "";
//生成起始序列值
int seekSeek = unchecked((int) DateTime.Now.Ticks);
Random seekRand = new Random(seekSeek);
int beginSeek = (int) seekRand.Next(, Int32.MaxValue - length*);
int[] seeks = new int[length];
for (int i = ; i < length; i++)
{
beginSeek += ;
seeks[i] = beginSeek;
}
//生成随机数字
for (int i = ; i < length; i++)
{
Random rand = new Random(seeks[i]);
int pownum = *(int) Math.Pow(, length);
randMembers[i] = rand.Next(pownum, Int32.MaxValue);
}
//抽取随机数字
for (int i = ; i < length; i++)
{
string numStr = randMembers[i].ToString();
int numLength = numStr.Length;
Random rand = new Random();
int numPosition = rand.Next(, numLength - );
validateNums[i] = Int32.Parse(numStr.Substring(numPosition, ));
}
//生成验证码
for (int i = ; i < length; i++)
{
validateNumberStr += validateNums[i].ToString();
}
return validateNumberStr;
} /// <summary>
/// 创建验证码的图片
/// </summary>
/// <param name="containsPage">要输出到的page对象</param>
/// <param name="validateNum">验证码</param>
public byte[] CreateValidateGraphic(string validateCode)
{
Bitmap image = new Bitmap((int) Math.Ceiling(validateCode.Length*12.0), );
Graphics g = Graphics.FromImage(image);
try
{
//生成随机生成器
Random random = new Random();
//清空图片背景色
g.Clear(Color.White);
//画图片的干扰线
for (int i = ; i < ; i++)
{
int x1 = random.Next(image.Width);
int x2 = random.Next(image.Width);
int y1 = random.Next(image.Height);
int y2 = random.Next(image.Height);
g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2);
}
Font font = new Font("Arial", , (FontStyle.Bold | FontStyle.Italic));
LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(, , image.Width, image.Height),
Color.Blue, Color.DarkRed, 1.2f, true);
g.DrawString(validateCode, font, brush, , );
//画图片的前景干扰点
for (int i = ; i < ; i++)
{
int x = random.Next(image.Width);
int y = random.Next(image.Height);
image.SetPixel(x, y, Color.FromArgb(random.Next()));
}
//画图片的边框线
g.DrawRectangle(new Pen(Color.Silver), , , image.Width - , image.Height - );
//保存图片数据
MemoryStream stream = new MemoryStream();
image.Save(stream, ImageFormat.Jpeg);
//输出图片流
return stream.ToArray();
}
finally
{
g.Dispose();
image.Dispose();
}
} /// <summary>
/// 得到验证码图片的长度
/// </summary>
/// <param name="validateNumLength">验证码的长度</param>
/// <returns></returns>
public static int GetImageWidth(int validateNumLength)
{
return (int) (validateNumLength*12.0);
} /// <summary>
/// 得到验证码的高度
/// </summary>
/// <returns></returns>
public static double GetImageHeight()
{
return 22.5;
}
}

然后写HtmlHelper类型的扩展方法,以便在View中调用。

  public static class HtmlExtensions
{
/// <summary>
/// 生成验证码
/// </summary>
/// <param name="helper">当前View的HtmlHelper</param>
/// <param name="urlHelper">当前View的UrlHelper</param>
/// <returns>带验证码的Img</returns>
public static MvcHtmlString GenerateCaptcha(this HtmlHelper helper, UrlHelper urlHelper)
{
var sb = new StringBuilder();
var builder = new TagBuilder("img");
builder.Attributes.Add("id", "captcha");
builder.Attributes.Add("style", "cursor:pointer");
builder.Attributes.Add("src", urlHelper.Action("GetCaptcha", "Common"));
builder.Attributes.Add("alt", "单击刷新验证码");
sb.AppendLine(builder.ToString(TagRenderMode.Normal)); sb.AppendLine("<script>");
sb.AppendLine("$(function(){");
sb.AppendLine("$('#captcha').bind('click',function(){this.src='" +
urlHelper.Action("GetCaptcha", "Common") + "?time='+(new Date()).getTime()})");
sb.AppendLine("})");
sb.AppendLine("</script>"); return MvcHtmlString.Create(sb.ToString());
} /// <summary>
/// 生成验证码
/// </summary>
/// <typeparam name="TModel">Model</typeparam>
/// <typeparam name="TValue">Model的值</typeparam>
/// <param name="helper">当前View的HtmlHelper</param>
/// <param name="expression">Model属性的Lambda表达式</param>
/// <param name="urlHelper">当前View的UrlHelper</param>
/// <returns>封装好的label,textbox,带验证码的img</returns>
public static MvcHtmlString GenerateCaptcha<TModel, TValue>(this HtmlHelper<TModel> helper,
Expression<Func<TModel, TValue>> expression, UrlHelper urlHelper)
{
StringBuilder sb = new StringBuilder();
var label = helper.LabelFor(expression, new {}, ":");
var textbox = helper.TextBoxFor(expression);
var captcha = GenerateCaptcha(helper, urlHelper);
sb.AppendLine(label.ToHtmlString());
sb.AppendLine(textbox.ToHtmlString());
sb.AppendLine(captcha.ToHtmlString()); return MvcHtmlString.Create(sb.ToString());
}
}

其中builder.Attributes.Add("src", urlHelper.Action("GetCaptcha", "Common"))调用了用于生成带验证码的GetCaptcha方法,该方法后面会提到,本人写在
CommonController当中,GetCaptcha方法其实就是调用了上面的CaptchaRender类中的CreateValidateCode方法,生成验证码输出到View。

GenerateCaptcha<TModel, TValue>这个泛型方法可以绑定视图模型中验证码的字段,并且生成label,textbox,image标签,还有相关的脚本,在View中输出的内容如下:

<label for="Captcha">验证码:</label>
<input id="Captcha" name="Captcha" type="text" value="" />
<img alt="单击刷新验证码" id="captcha" src="/Common/GetCaptcha" style="cursor:pointer"></img>
<script>
$(function(){
$('#captcha').bind('click',function(){this.src='/Common/GetCaptcha?time='+(new Date()).getTime()})
})
</script>

CommonController中的GetCaptcha方法如下:

        /// <summary>
/// 生成验证码
/// </summary>
/// <returns></returns>
public ActionResult GetCaptcha()
{
CaptchaRender captcha = new CaptchaRender();
string code = captcha.CreateValidateCode();
TempData["Captcha"] = code;
byte[] bytes = captcha.CreateValidateGraphic(code);
return File(bytes, "image/jpeg");
}

TempData["Captcha"] = code是把生成的验证码放到TempData中,以便在ActionFilter中获取到验证码的值,ActionFilter方法如下:

     public class CaptchaValidatorAttribute : ActionFilterAttribute
{
private const string CaptchaFormValue = "Captcha";
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
bool valid = false; foreach (var value in filterContext.HttpContext.Request.Form.AllKeys)
{
if (value.Contains(CaptchaFormValue))
{
valid = (string) filterContext.Controller.TempData["Captcha"] ==
filterContext.HttpContext.Request.Form[value];
break;
}
}
filterContext.ActionParameters["captchaValid"] = valid;
base.OnActionExecuting(filterContext);
}
}

CaptchaValidator过滤器其实就是在相应的Action执行前,遍历Form窗体变量集合的所有Key值,把保存在TempData["Captcha"]中的验证码的值和Form窗体中name="Captcha"(Key值="Captcha")的Textbox的值(用户输入的验证码)比较,然后再把比较后的bool值赋值给用CaptchaValidator特性修饰的Action的captchaValid参数。(Action根据captchaValid参数的值去判断是否通过验证)。

View视图代码调用如下:

@Html.GenerateCaptcha(m => m.Captcha, Url)

Action调用如下:

一定要记得Action的参数名称captchaValid和过滤器中 filterContext.ActionParameters["captchaValid"]一致。

效果图如下:

MVC采用HtmlHelper扩展和Filter封装验证码的功能的更多相关文章

  1. MVC 自定义Htmlhelper扩展

    在MVC中,我们不仅可以使用它原来的方法,我们还可以自定义,这不不仅加大了我们开发的效率,同时使界面更简洁. 具体什么是扩展方法,你可以这样理解,必须是静态且在形参中第一个参数是以this开头,大概先 ...

  2. asp.net MVC添加HtmlHelper扩展示例和用法

    一.先创建一个HtmlHelper的扩展类,代码: using System; using System.Collections.Generic; using System.Linq; using S ...

  3. ASP.NET MVC Razor HtmlHelper扩展和自定义控件

    先看示例代码: using System; using System.Collections.Generic; using System.Linq; using System.Web; using S ...

  4. .net mvc HtmlHelper扩展使用

    如果是你是从webform开始接触.net,你应该记得webform开发中,存在自定义控件这东西,它使得我们开发起来十分方便,如今mvc大势所趋,其实在mvc开发时,也存在自定义控件这么个东西,那就是 ...

  5. MVC HtmlHelper扩展——实现分页功能

    MVC HtmlHelper扩展类(PagingHelper) using System; using System.Collections.Generic; using System.Collect ...

  6. 【ASP.NET MVC系列】浅谈ASP.NET MVC八大类扩展(上篇)

    lASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操 ...

  7. ASP.NET + MVC5 入门完整教程四---MVC 中使用扩展方法

    https://blog.csdn.net/qq_21419015/article/details/80433640 1.示例项目准备1)项目创建新建一个项目,命名为LanguageFeatures ...

  8. [Asp.net Mvc]通过UrlHelper扩展为js,css静态文件添加版本号

    写在前面 在app中嵌入h5应用,最头疼的就是缓存的问题,比如你修改了一个样式,或者在js中添加了一个方法,发布之后,并没有更新,加载的仍是缓存里面的内容.这个时候就需要清理缓存才能解决.但又不想让w ...

  9. MVC中HtmlHelper用法大全参考

    MVC中HtmlHelper用法大全参考 解析MVC中HtmlHelper控件7个大类中各个控件的主要使用方法(1) 2012-02-27 16:25 HtmlHelper类在命令System.Web ...

随机推荐

  1. 【mysql】关于Index Condition Pushdown特性

    ICP简介 Index Condition Pushdown (ICP) is an optimization for the case where MySQL retrieves rows from ...

  2. 标准sql语句,学习

    标准SQL语句总结标准SQL语句总结,标准SQL语言基本上适用于下面所列出的数据库软件 -------------------------------------------------------- ...

  3. ajaxFileUpload文件上传

    一.简介 ajaxFileUpload是一种异步的文件上传控件,通过ajax进行文件上传,并获取上传处理结果.在很多时候我们需要使用到文件上传的功能,但是不需要使用那些强大的上传插件.此时就可以使用a ...

  4. HDU 4050 wolf5x(动态规划-概率DP)

    wolf5x Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  5. linux动态网络和静态网络和克隆后的网络配置

    建议设置网卡NAT模式 动态网络配置:1.一定要开启本地DHCP服务 2.在虚拟网络编辑器中选择NAT模式选中DHCP项如下图 3.ifup eth0 静态网络配置 : 注释:ifcfg-eth0部分 ...

  6. 【VB超简单入门】三、开始编程

    接下来要进入正题了!同学们要认真看咯~ 第一步:安装VB开发IDE 在这里我推荐大家安装的是VB迷你版,现在大多数同学使用win7,这个版本可以在win7上运行的妥妥的~ 下载链接:http://pa ...

  7. sqlserver 2005 分布式架构 对等事务复制 .

    http://www.cnblogs.com/qanholas/archive/2012/03/22/2412444.html     一.为什么要使用对等事务复制 首先要说明的是使用sqlserve ...

  8. Dubbo架构设计详解(转自shiyanjun.cn)

    Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合).从服务模型的角度来看,Dubbo采用的是一种非常简单的模 ...

  9. 合工大 OJ 1332 蛇形阵

    Description 蛇形针回字阵: 如3*3: 回字阵: 7 6 5 8 1 4 9 2 3 Input 多组数据: 每一行一个正整数n(n为奇数,<26),代表n*n矩阵. Output ...

  10. codeforces 719E E. Sasha and Array(线段树)

    题目链接: E. Sasha and Array time limit per test 5 seconds memory limit per test 256 megabytes input sta ...