WebSite---前台系统图片验证码心得
背景: 因为移动端APP和Msite手机注册发送短信验证码没有添加图片验证码功能。公司的短信接口被恶意刷取。所以我们就觉得在移动端添加一个图片验证码功能。分享一下大体实现方式思路。PS demo是自己写的。跟公司代码还是有很大差距的。
一. 图片验证码第一版
1. 建立图片验证码 ValidationCodeHelper
1.1 填写方法生成对应的.验证码: 默认是4位数字
private static char[] _constant = {
'','','','','','','','','','',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
};
public static string CreateValidateCode(int length = , bool isNum = true)
{
var sb = new StringBuilder();
var constant = isNum ? _constant.Take().ToArray() : _constant;
var constant_count = constant.Count();
Random rd = new Random();
for (var index = ; index < length; index++)
{
sb.Append(constant[rd.Next(constant_count)]);
}
return sb.ToString();
}
1.2 通过验证码生成图片流, 此代码是从其他博友那里Copy过来的。自己对图片方面不擅长
public static byte[] GetImage(string code)
{
Bitmap image = new Bitmap((int)Math.Ceiling(code.Length * 16.0), );
Graphics g = Graphics.FromImage(image);
try
{
Random random = new Random();
g.Clear(Color.Gray);
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, x2, y1, 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(code, 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();
}
catch (Exception ex)
{
return null;
}
finally
{
g.Dispose();
image.Dispose();
}
}
2. 封装一个简单的CookieHelper类型主要是对Cookie进行加密。只是简单封装, 没有对CookieHelper添加泛型,未支持Object处理。公司里面的CookieHelper库更强大。可是不能分享代码出来。所以自己简单的写了一个。
public class CookieHelper
{ #region 字符串加密解密 private static string _MD5 = "8ff0c65d-a2ed-4e1e-af85-690c08b8d039"; private static string Decrypt(string cipherString)
{
byte[] keyArray;
byte[] toEncryptArray = Convert.FromBase64String(cipherString);
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(_MD5));
hashmd5.Clear(); TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(
toEncryptArray, , toEncryptArray.Length);
tdes.Clear();
return UTF8Encoding.UTF8.GetString(resultArray);
} private static string Encrypt(string toEncrypt)
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(_MD5));
hashmd5.Clear(); TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7; ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray =
cTransform.TransformFinalBlock(toEncryptArray, ,
toEncryptArray.Length);
tdes.Clear();
return Convert.ToBase64String(resultArray, , resultArray.Length);
} #endregion #region Cookie public static void SaveCookie(string name, string value, int expiredSecond = )
{
var encryptStr = Encrypt(value);
var collection = HttpContext.Current.Response.Cookies;
collection.Add(new HttpCookie(name)
{
Value = encryptStr,
Expires = expiredSecond > ? System.DateTime.Now.AddSeconds(expiredSecond) : System.DateTime.MaxValue
});
} public static string GetCookie(string name)
{
var cookie = HttpContext.Current.Request.Cookies.Get(name);
if (cookie == null)
{
return null;
}
else
{
return Decrypt(cookie.Value);
}
} #endregion
}
3. Controller新增图片服务。设置图片的Cookie有效期是一分钟
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
} public FileContentResult ImageValidator()
{
var code = ValidationCodeHelper.CreateValidateCode();
CookieHelper.SaveCookie("PicCode", code, );
var picByte = ValidationCodeHelper.GetImage(code);
return File(picByte, "image/jpeg ");
} /// <summary>
/// 检查图片验证码是否正确
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
public ActionResult CheckPicCode(string code)
{
var cookieCode = CookieHelper.GetCookie("PicCode");
if (string.IsNullOrWhiteSpace(cookieCode))
{
return Json("验证码过期",JsonRequestBehavior.AllowGet);
}
if (code.Trim().ToUpper() == cookieCode.ToUpper())
{
return Json("验证码正确",JsonRequestBehavior.AllowGet);
}
else
{
return Json("验证码错误",JsonRequestBehavior.AllowGet);
}
}
}
4.前台页面. 通过修改img的src链接,来实现点击刷新图片.
<head>
<title></title>
<script src="https://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<input type="text" id="inpCode" />
<img id="picCode" src="/Home/ImageValidator" />
<button id="btnCheck" >校验</button>
</body>
</html>
<script> $(function () { $("#picCode").on('click', function () {
$(this).attr('src', "/Home/ImageValidator?v=" + new Date().getTime());
}) $("#btnCheck").on('click', function () {
$.ajax({
type: 'get',
url: "/Home/CheckPicCode",
data: {
code:$("#inpCode").val()
},
success: function (data) {
alert(data);
}
})
}) }) </script>
5. 第一版基本代码实现了,点击图片刷新验证码,图片验证码有效期是一分钟.
一分钟内

一分钟后,验证码过期了

6.大家看上面两张图以为验证码OK了。的确。正常网站使用是OK的。因为我们设置了验证码的有效时间是一分钟。那我们看看Fiddler里面的效果。
当我面在Fiddler里面模拟的时候Cookie的过期时间是没有的。也就是如果客户端用户抓取了PicCode的Cookie后。自己构建请求的话。Cookie是不会失效的。


二. 图片验证码改版。
从上面看来 直接设置Cookie的过期时间是不行的。那我们只能在Cookie存储Value上修改了。来看看我们代码实现方式。我们将过期时间的ticks和验证码字符串同时加密存储在了Cookie中。
/// <summary>
/// 构建图片Cookie字符串,code和过期见时间用逗号隔开
/// </summary>
public static string BuildValidateCodeStorage(string code, int expiredSeconds = )
{
return string.Format("{0},{1}", code, System.DateTime.Now.AddSeconds(expiredSeconds).Ticks);
}
/// <summary>
/// 解析图片验证码Cookie
/// </summary>
public static string AnysisValidateCode(string codeStorage)
{
if (string.IsNullOrWhiteSpace(codeStorage))
{
return null;
}
else
{
var vals = codeStorage.Split(',');
if (vals.Count() != )
{
return null;
}
else
{
long ticks = ;
long.TryParse(vals[], out ticks);
if (ticks > System.DateTime.Now.Ticks)
{
return vals[];
}
else
{
return null;
}
}
}
}
三.总结
这个是我们暂时想到的图片验证码实现方案。不知道其他博友公司是如何实现的。希望大家也可以分享一下。
http://files.cnblogs.com/files/FourLeafCloverZc/ImageValidation.zip
WebSite---前台系统图片验证码心得的更多相关文章
- Django实战(一)-----用户登录与注册系统5(图片验证码)
为了防止机器人频繁登录网站或者破坏分子恶意登录,很多用户登录和注册系统都提供了图形验证码功能. 验证码(CAPTCHA)是一种区分用户是计算机还是人的公共全自动程序. 可以防止恶意破解密码.刷票.论坛 ...
- 项目一:第八天 1、前台系统导入 实现客户注册 发验证码,邮件 springdata-redis存储数据 3、实现客户登陆
1 前台系统客户注册功能 页面:signup.html 1.1 验证手机号是否注册(邮箱同样) 1. 使用Jquery-validate插件进行相关校验,使用校验规则 <input type=& ...
- dedecms织梦系统后台验证码图片不显示的解决方法
网站迁移后,dedecms织梦系统后台验证码图片不显示的解决方法通用解决方案-取消后台验证码功能因为没有验证码,不能进后台,所以修改php文件源代码:方法一:打开dede/login.php 找到如下 ...
- 潭州课堂25班:Ph201805201 django 项目 第九课 图片验证码前台实现,判断用户是否注册功能实现 (课堂笔记)
u胎代码实现 : 针对每一个 app 写个 js 脚本, 先给 users 的 app 应用创建个 js:在指定目录下的 js 文件夹下,创建 users 文件夹,下创建 suth.js ,图片验证 ...
- Webform 文件上传、 C#加图片水印 、 图片验证码
文件上传:要使用控件 - FileUpload 1.如何判断是否选中文件? FileUpload.FileName - 选中文件的文件名,如果长度不大于0,那么说明没选中任何文件 js - f.val ...
- 字符型图片验证码识别完整过程及Python实现
字符型图片验证码识别完整过程及Python实现 1 摘要 验证码是目前互联网上非常常见也是非常重要的一个事物,充当着很多系统的 防火墙 功能,但是随时OCR技术的发展,验证码暴露出来的安全问题也越 ...
- webform(十)——图片水印和图片验证码
两者都需要引入命名空间:using System.Drawing; 一.图片水印 前台Photoshuiyin.aspx代码: <div> <asp:FileUpload ID=&q ...
- php 图片验证码生成 前后台验证
自己从前一段时间做了个php小项目,关于生成图片验证码生成和后台的验证,把自己用到的东西总结一下,希望大家在用到相关问题的时候可以有一定的参考性. 首先,php验证码生成. 代码如下: 1.生成图像代 ...
- ASP.NET MVC 模块与组件(二)——定制图片验证码
本着简洁直接,我们就直奔主题吧! 下面是一个生成数字和字母随机组合的验证码类源代码: using System; using System.Drawing; using System.Drawing ...
随机推荐
- php 中 php-fpm 的重启、终止操作命令
php-fpm没有启动nginx会报502的错误 php 5.3.3 下的php-fpm 不再支持 php-fpm 以前具有的 /usr/local/php/sbin/php-fpm (start|s ...
- 基于ASIO的协程与网络编程
协程 协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态.协程可以在运行期间的某个点上暂停执行,并在恢复运行时从暂停的点上继续执行. 协程 ...
- HMX-Server C++ 分步式服务器大版本更新了(有源码)
原文地址:http://www.cnblogs.com/hellohuang/p/6294763.html # HMX-ServerHMX-Server分步式服务器框架,主要分为网关.登录.世界.场景 ...
- office如何去除多页签
写文档会遇到同时打开多个文档,偶尔可能需要对比,而有时office会出现跟浏览器类似的多页签界面.如何去除多页签,office本身没有此加载项,一般都是作为插件或组件形式另外安装,导致我们不知道从哪里 ...
- 通过java.net.URLConnection发送HTTP请求的方法
一.前言 如何通过Java发送HTTP请求,通俗点讲,如何通过Java(模拟浏览器)发送HTTP请求. Java有原生的API可用于发送HTTP请求,即java.net.URL.java.net.UR ...
- 百叶窗特效(用move.js库)
每逢佳节胖三斤啊,胖了胖了,加上每天坐在电脑前,现在还和一个智障聊天,后天去苏州玩的事情,住哪里啊?去哪里嘿嘿嘿啊? 苏州,找了下,攻略,听说一定要去园林看,听说很牛逼,好吧,陶冶一下我的情操.今天操 ...
- Java中boolean类型到底占用多少字节
虽然 Java 虚拟机定义了 boolean 这种数据类型,但是只对它提供了非常有限的支持.在 Java 虚拟机中没有任何供 boolean 值专用的字节码指令,在 Java 语言之中涉及到 bool ...
- C++编程练习(6)----“实现简单的队列的链式存储结构“
队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出.简称链队列. 实现代码如下: /* LinkQueue.h 头文件 */ #include<iostream> #defi ...
- ArcGIS制图技巧系列(2)地形渲染
ArcGIS制图技巧系列(2)地形渲染 by 李远祥 DEM数据是常见的地形数据,在GIS常规的制图中,DEM一直扮演着增强效果.由于带有高程值,DEM在很多情况下都在三维中显示,但这里主要介绍的是在 ...
- 性能秒杀log4net的NLogger日志组件(附测试代码与NLogger源码)
NLogger特性: 一:不依赖于第三方插件和支持.net2.0 二:支持多线程高并发 三:读写双缓冲对列 四:自定义日志缓冲大小 五:支持即时触发刷盘机制 六:先按日期再按文件大小滚动Rolling ...