MVC采用HtmlHelper扩展和Filter封装验证码的功能
最近因为有个项目除了登录还有其他很多地方需要用到验证码的功能,所以想到了采用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封装验证码的功能的更多相关文章
- MVC 自定义Htmlhelper扩展
在MVC中,我们不仅可以使用它原来的方法,我们还可以自定义,这不不仅加大了我们开发的效率,同时使界面更简洁. 具体什么是扩展方法,你可以这样理解,必须是静态且在形参中第一个参数是以this开头,大概先 ...
- asp.net MVC添加HtmlHelper扩展示例和用法
一.先创建一个HtmlHelper的扩展类,代码: using System; using System.Collections.Generic; using System.Linq; using S ...
- ASP.NET MVC Razor HtmlHelper扩展和自定义控件
先看示例代码: using System; using System.Collections.Generic; using System.Linq; using System.Web; using S ...
- .net mvc HtmlHelper扩展使用
如果是你是从webform开始接触.net,你应该记得webform开发中,存在自定义控件这东西,它使得我们开发起来十分方便,如今mvc大势所趋,其实在mvc开发时,也存在自定义控件这么个东西,那就是 ...
- MVC HtmlHelper扩展——实现分页功能
MVC HtmlHelper扩展类(PagingHelper) using System; using System.Collections.Generic; using System.Collect ...
- 【ASP.NET MVC系列】浅谈ASP.NET MVC八大类扩展(上篇)
lASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操 ...
- ASP.NET + MVC5 入门完整教程四---MVC 中使用扩展方法
https://blog.csdn.net/qq_21419015/article/details/80433640 1.示例项目准备1)项目创建新建一个项目,命名为LanguageFeatures ...
- [Asp.net Mvc]通过UrlHelper扩展为js,css静态文件添加版本号
写在前面 在app中嵌入h5应用,最头疼的就是缓存的问题,比如你修改了一个样式,或者在js中添加了一个方法,发布之后,并没有更新,加载的仍是缓存里面的内容.这个时候就需要清理缓存才能解决.但又不想让w ...
- MVC中HtmlHelper用法大全参考
MVC中HtmlHelper用法大全参考 解析MVC中HtmlHelper控件7个大类中各个控件的主要使用方法(1) 2012-02-27 16:25 HtmlHelper类在命令System.Web ...
随机推荐
- 微信公众平台应用开发:方法、技巧与案例--柳峰,Java语言版本
他本人的博客:http://blog.csdn.net/lyq8479 作者简介: 刘运强,网名“柳峰”,资深微信公众平台应用开发工程师,国内微信公众平台应用开发的先驱之一,项目经验丰富.他还是一位资 ...
- 利用API方式进行数据库的增删改查
/* 将数据库的增删改查单独放进一个包 */ package com.itheima28.sqlitedemo.dao; import java.util.ArrayList; import java ...
- ZOJ 3865 Superbot(优先队列--模板)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5477 主要思路:1.从一个点(cur)到它相邻的点(next),所需 ...
- Linux之存储及文件系统管理
一.存储管理 1.各种存储设备在Linux系统中对应的文件名 2.硬盘结构及分区 1).硬盘结构 2) .为什么要进行硬盘分区: a) 更容易管理和控制系统,因为相关的文件和目录都放在一个分区中. b ...
- cut
cut是一个针对行的数据选取命令 SYNOPSIS cut [OPTION]... [FILE]... OPTION -b 以字节为单位进行分割,如果是多字节的话就需要注意了 -c 以字符为单位进行分 ...
- Mysql在windows下和linux下对表名大小写默认要求的一个细节
今天在虚拟机里搭建项目环境,偷了下懒,直接把本机数据库中的表用sqlyog复制给虚拟机中的数据库,然后开始部署项目,项目一启动提示: Table 'sdmqrt.QRTZ_LOCKS' doesn't ...
- 动手学习TCP:客户端状态变迁
上一篇文章中介绍了TCP连接的建立和终止. 通过实际操作了解到,在TCP协议工作过程中,客户端和服务端都会接收或者发送特定标志的TCP数据包,然后进入不同的状态. 也就是说,TCP协议就是一个包含多种 ...
- CSS 属性 :before && :after的用法,伪类和伪元素的区别
一::before && :after的用法 :before 如同对伪元素的名称一样,:before 是用来给指定的元素的内容前面插入新的内容.举例说明: .before:before ...
- n个整数中,找出尽可能多的数使他们组成一个等差数列,求最长等差数列的长度
例子: 3,8,4,5,6,2 返回值应该为 :5 这是昨天做的一道优酷土豆的编程题,和leetcode中的128/ Longest Consecutive Sequence 有点 ...
- linux之间进程通信
进程间通信方式: 同主机进程间数据交换机制: pipe(无名管道) / fifo(有名管道)/ message queue(消息队列)和共享内存. 必备基础: f ...