最近因为有个项目除了登录还有其他很多地方需要用到验证码的功能,所以想到了采用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. hdu 4856 Tunnels (记忆化搜索)

    Tunnels Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Su ...

  2. Hadoop question list

    1.我们在开发普通的web app的时候,总会用到orm框架,如hibernates ,ibates等,在hadoop中我们一直使用writable对象,当然如果我们想实现自己的对象类,需要继承这个w ...

  3. ssis trainning

    1. 防止包打开后hang住,可以使用delay validation=false. 2.2008R2 configuration 起作用的优先级? 一是des ign time. 二是运行的时候指定 ...

  4. OpenStack虚拟机状态

    OpenStack创建一个虚拟机,涉及到三种状态,vm_state,task_state和power_state. 先总结几点: 电源状态(power_state):是hypervisor的状态,从计 ...

  5. A Personal Selection of Books on E lectromagnetics and Computational E lectromagnetics---David B. Davidson

    链接. General Books on Electromagnetics When our department recently reviewed our junior-level text, w ...

  6. 倍增法-lca codevs 1036 商务旅行

    codevs 1036 商务旅行  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题目描述 Description 某首都城市的商人要经常到各城镇去做生意 ...

  7. UESTC 886 方老师金币堆 --合并石子DP

    环状合并石子问题. 环状无非是第n个要和第1个相邻.可以复制该行石子到原来那行的右边即可达到目的. 定义:dp[i][j]代表从第i堆合并至第j堆所要消耗的最小体力. 转移方程:dp[i][j]=mi ...

  8. UESTC 900 方老师炸弹 --Tarjan求割点及删点后连通分量数

    Tarjan算法. 1.若u为根,且度大于1,则为割点 2.若u不为根,如果low[v]>=dfn[u],则u为割点(出现重边时可能导致等号,要判重边) 3.若low[v]>dfn[u], ...

  9. nginx 一二事(2) - 创建虚拟静态服务器

    一.什么是nginx 是一个C语言开发的HTTP反向代理服务器,性能非常高 一个俄罗斯的哥们开发的,官方提供的测试性能能够达到5W的并发,我的天呐~,实际测试差不多是2W,而淘宝的牛人可以优化到200 ...

  10. [cb]Unity 项目架构

    一.技能机制 二.游戏工程 三.客户端架构