ASP.NET.MVC实现网站验证码功能

开发工具与关键技术:Visual Studio 2015  生成验证码
作者:孙水兵
撰写时间:2019年5月7

一、为什么网站要用到验证码
因为WEB站有时会碰到客户机恶意攻击,其中一种很常见的攻击手段就是 身份欺骗_它通过 在客户端脚本写入一些代码,然后利用其,客户机在网站,论坛反复登陆,或者攻击者创建一个HTML窗体,其窗体如果包含了你注册窗体或发帖窗体等相同的字段,然后利用"http-post"传输数据到服务器,服务器会执行相应的创建帐户,提交垃圾数据等操作,如果服务器本身不能有效验证并拒绝此非法操作,它会很严重耗费其系统资源,降低网站性能甚至使程序崩溃。(来自搜狗问问https://wenwen.sogou.com/z/q780650284.htm )
二、验证码的作用
验证码实际上是一种Web自动程序, 它有多种形式,比如手机验证码、语音验证码、视频验证码等等多种形式,主要目的还是出于对网站用户的保护,简单分类,可以有如下四个方面:

  1. 防恶意破解密码:比如百度,随便输入一个帐号,如果密码错误,马上会出现验证码
  2. 防论坛灌水:这个是很常见的。有一种程序叫做顶帖机,如果无限制的刷,整个论坛可能到处是拉圾信息,比如,百度贴吧 ,你只要是新用户或者刚刚关注的贴吧,要是发帖,会马上出现验证码
  3. 防止有人利用机器人进行批量注册
  4. 防刷票,网上有很多投票类的网站,比如评选最美中国人(举个例子)。如果不出验证码,会有恶意的刷票行为。(来自百度经验https://jingyan.baidu.com/article/00a07f3840a93b82d028dcb9.html)

三、生成验证码的公共静态类ValidCodeUtils详解
1、创建一个公共静态类ValidCodeUtils。即另外声明一个类文件ValidCodeUtils将其改为静态类文件。
在这里插入图片描述
2、在公共静态类文件ValidCodeUtils中写生成随机数的方法和根据字符串创建验证码图片
产生随机数的方法getRandomCode
写一个静态类的产生随机数的方法getRandomCode,并传入一个int类型的参数(产生随机数的长度)。生命一个string类型的变量strReturn并让他为空。实例化Random产生随机数(Random 一种能够产生满足某些随机性统计要求的数字序列设备)。for循环,for循环的次数为产生随机数的长度。在for循环中,声明一个char类型的变量cRerult,然后产生一个非负随机整数并用intRandom接收。判断:如果非负随机整数intRandom除以3取余数等于0,变量cRerult为十六进制的30(十进制的48)加上非负随机整数intRandom除以10的余数并将其强制转换为char类型,以此来达到产生数字的目的。(在这里用到了ASCLL码,而在ASCLL码中,4857代表09。而任何数除以10的余数为0到9,所以十六进制的30(十进制的48)加上非负随机整数intRandom除以10的余数在十进制中的的范围为48到57,将其转换成char类型即为0到9。从而达到产生数字的目的)。如果非负随机整数intRandom除以3取余数等于1,变量cRerult为十六进制的41(十进制的65)加上非负随机整数intRandom除以十六进制的1a(十进制的26)的余数并将其强制转换为char类型(在ASCLL码中,65到97表示大写的字母A到Z,而任何数除以26的余数为0到25,因此十六进制的41(十进制的65)加上非负随机整数intRandom除以十六进制的1a(十进制的26)的取值范围为65到95,最后将其转换成将其转换成char类型即为A到Z。从而达到产生字母的目的)。如果非负随机整数intRandom除以3取余数不等于0或1。变量cRerult为十六进制的61(十进制的97)加上非负随机整数intRandom除以十六进制的1a(十进制的26)的余数并将其强制转换为char类型(在ASCLL码中, 97到122表示小写的字母a到z)。以此来达到产生小写的字母a~z的目的。在for循环外拼接变量cRerult并转换成string类型,用变量strReturn来接收拼接的变量cRerult并返回。
在这里插入图片描述
根据字符串创建验证码图片
创建一个数组类静态方法CreateImage,并传入一个string类型的参数strRandom(生成随机的验证码字符串)。在方法中,new一个宽为生成随机的验证码字符串*20,高为38的图片。再在绘画图面上定义一支画笔g,然后清除整个绘画图面,并以白色填充整个绘画图面。定义红色画笔。在白色绘画图面上坐标为(12,4)的地方用红色的画笔以字体为"Aril",字体大小为18来画生成验证码字符串。为防止机器,需绘制干扰线和干扰点。new一个随机类random,for循环10次,即画10条干扰线。在for循环中,要随机获取两个点的坐标,干扰线的两个端点坐标(x1,y1)、(x2,y2),从而达到绘制一条干扰线的目的。并且x轴的不能超过图片的宽度,y轴不能超过图片的高度。为防止绘制的干扰线超出图片。然后以两个端点坐标(x1,y1)、(x2,y2)绘制灰色的干扰线。和绘制干扰线类似,随机绘制100个干扰点。For循环100次随机得到100个坐标,然后在图片上以随机坐标设置颜色随机的点。绘制蓝色的矩形边框。然后就将图片保存到内存流中,然后将内存流中的内容写入byte数组中返回。
在这里插入图片描述
四、生成验证码的代码
HTML代码
HTML代码部分很简单,最主要的部分是在from表单中的lable标签和input标签,以及div中的img标签。Img标签中的src为:/生成验证码的action所在的控制器/控制器中生成验证码的action的名称。以此达到打开网站,页面就会显示出验证码的效果。Width为验证码图片的宽的,height为验证码图片的高度。
在这里插入图片描述
调用ValidCodeUtils生成验证码
在控制器中创建一个名为CreateValidCodeImage的方法。在方法中调用静态类ValidCodeUtils中的随机生成字符串的方法getRandomCode,在getRandomCode方法中传入验证码的长度(5),声明一个变量strRandom用来接收调用方法getRandomCode生成的长度为5的随机字符串。在将得到的随机字符串传入ValidCodeUtils中的CreateImage方法,并将得到的随机字符串传入该方法中。将获取到的随机字符串保存到session中,用来后面判断验证码是否正确。最后将得到的验证码图片返回。
在这里插入图片描述
这样就可以初步显示验证码了,不过不能切换验证码。

JS代码—切换验证码
给验证码图片写一个点击事件,用post方法将验证码切换的路径(/生成验证码的action所在的控制器/控制器中生成验证码的action的名称)返回到img标签中的src中。这样每点击一次图片就会切换一次验证码。但是由于浏览器的缓存机制,当用户调用一次验证码切换的路径时,浏览器会将该路径缓存下来,当用户再次请求该路径时,缓存机制会将之前缓存的路径调用。验证码图片就不会更改。每次切换验证码后需要清理一次缓存。但是,我们不可能让用户每切换一次验证码都清理一次缓存,因此在验证码切换的路径后面拼接一个参数t,后面加上时间(以毫秒计), 每一毫秒更改一次验证码切换的路径。从而克服缓存机制的干扰。
在这里插入图片描述
JS代码—提交验证码
给验证码的提交按钮写一个点击事件,获取页面得到的验证码用变量validCodeImg来接收,然后判断验证码是否为null、空字符串、undefined。然后用post提交获取到的验证码。用data接收页面返回的数据,输出控制器返回的文本。
在这里插入图片描述
控制器代码——判断验证码是否正确
创建一个方法UserLogin并接收视图传入的验证码。声明变量returnJsonText、sessionValidCode分别用来接收返回视图的文本和从session中获取的验证码。捕获异常,获取session中的验证码,并用sessionValidCode接收。然后判断从session中获取的验证码是否与视图传入的验证码一致并且忽略大小写。如果一致,继续往下执行,反之,输出验证码错误,返回returnJsonText。
StringComparison.CurrentCultureIgnoreCase:使用区域敏感排序规则、当前区域来比较字符串,同时忽略被比较字符串的大小写。

在这里插入图片描述

生成验证码的类

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Web;

namespace CQUPBootstrap4.Common
{
    /// <summary>
    /// 公共静态
    /// </summary>
    public static class ValidCodeUtils //公共静态
    {
        /// <summary>
        /// 获得随机字符串
        /// </summary>
        /// <param name="intLength">随机数的长度</param>
        /// <returns>随机数字符串</returns>
        public static string GetRandomCode(int intLength)
        {
            /*产生数字和密码混合的随机数*/
            string strReturn = string.Empty;
            Random random = new Random();//随机数
            for (int i = 0; i < intLength; i++)
            {
                char cRerult;
                int intRandom = random.Next();//产生一个非负随机整数
                /*根据当前随机数来确定字符串*/
                //intRandom % 3 获取的是intRandom/3 得到的余数
                if (intRandom % 3 == 0)
                {
                    //产生数字
                    //位数来产生数字
                    cRerult = (char)(0x30 + (intRandom % 10));
                }
                else if (intRandom % 3 == 1)
                {
                    //位数产生大写字母:大写字符 65-97 A 65
                    //68 D  25 Z
                    cRerult = (char)(0x41 + (intRandom % 0x1a));
                }
                else
                {
                    //余数为2
                    //产生小写字母 98 -116
                    cRerult = (char)(0x61 + (intRandom % 0x1a));
                }
                strReturn += cRerult.ToString();
            }
            return strReturn;
        }

        /// <summary>
        /// 根据字符串创建验证码图片 
        /// </summary>
        /// <param name="strRandom">字符串</param>
        /// <returns>图片的二进制数组</returns>
        public static byte[] CreateImage(string strRandom)
        {
            //新增图片
            Bitmap newBitmap = new Bitmap(strRandom.Length * 20, 38);

            Graphics g = Graphics.FromImage(newBitmap);
            g.Clear(Color.White);
            //在图片上绘制文字
            SolidBrush solidBrush = new SolidBrush(Color.Red);
            g.DrawString(strRandom, new Font("Aril", 18), solidBrush, 12, 4);
            //在图片上绘制干扰线
            Random random = new Random();
            for (int i = 0; i < 10; i++)
            {
                //产生一条线,并绘制到画布。 起始点(x,y)  总结点
                int x1 = random.Next(newBitmap.Width);
                int y1 = random.Next(newBitmap.Height);
                int x2 = random.Next(newBitmap.Width);
                int y2 = random.Next(newBitmap.Height);
                g.DrawLine(new Pen(Color.DarkGray), x1, y1, x2, y2);
            }
            //绘制图片的前景干扰点
            for (int i = 0; i < 100; i++)
            {
                int x = random.Next(newBitmap.Width);
                int y = random.Next(newBitmap.Height);
                newBitmap.SetPixel(x, y, Color.FromArgb(random.Next()));
            }
            //在最外边绘制边框
            g.DrawRectangle(new Pen(Color.Blue), 0, 0, newBitmap.Width, newBitmap.Height);
            g.DrawRectangle(new Pen(Color.Blue), -1, -1, newBitmap.Width, newBitmap.Height);
            //将图转保存到内存流中
            MemoryStream ms = new MemoryStream();
            newBitmap.Save(ms, ImageFormat.Jpeg);
            return ms.ToArray();//将流内容写入byte数组返回
        }



    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值