引言
ASP.NET Core的验证码呢,稍微有一点曲折,因为默认System.Drawing没有Bitmap对象,也就没法绘制对象,不过通过NuGet:ZKWeb.System.Drawing 可引入Bitmap对象,进行验证码图片的绘制。
一、生成随机数
随机数就比较简单了,给定特定的字符数组,通过Random来生成随机数拼接成对应的字符串,就得到了我们的随验证码的随即字符,这里我简单进行了封装,仅供参考!
/// <summary>
/// 获取数字验证码
/// </summary>
/// <param name="n">验证码数</param>
/// <returns></returns>
public static string CreateNumCode(int n)
{
char[] numChar = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
string charCode = string.Empty;
Random random = new Random();
for (int i = 0; i < n; i++)
{
charCode += numChar[random.Next(numChar.Length)];
}
return charCode;
}
/// <summary>
/// 获取字符验证码
/// </summary>
/// <param name="n">验证码数</param>
/// <returns></returns>
public static string CreateCharCode(int n)
{
char[] strChar = {
'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','0','1','2','3',
'4','5','6','7','8','9','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'};
string charCode = string.Empty;
Random random = new Random();
for (int i = 0; i < n; i++)
{
charCode += strChar[random.Next(strChar.Length)];
}
return charCode;
}
二、绘制图片
绘制图片也就是所谓的验证码对于新手就比较陌生了,不过也很好理解,通过简单的梳理下逻辑步骤,就可以清晰明了。即:通过Bitmap来创建画布,Graphis执行画的动作,如:验证码的躁线、噪点、呈现的字符,通过MemoryStream写入内存,通过MemoryStream转换的流数据去获取生成的对应验证码图,再用Session或Cookie存储验证码即可完成!
1、画布
通过Bitmap对象创建画布
//创建画布
Bitmap bitmap = new Bitmap(codeW, codeH);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.Clear(Color.White);
2、画躁线
躁线可提高验证码的可用性,通过给Graphics画笔Pen指定颜色、位置即可完成!
//颜色列表
Color[] colors = {
Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.DarkBlue };
//宽、高,字体大小
int codeW = 74;
int codeH = 36;
int fontSize = 16;
Random random = new Random();
//画躁线
for (int i = 0; i < n; i++)
{
int x1 = random.Next(codeW);
int y1 = random.Next(codeH);
int x2 = random.Next(codeW);
int y2 = random.Next(codeH);
Color color = colors[random.Next(colors.Length)];
Pen pen = new Pen(color);
graphics.DrawLine(pen, x1, y1, x2, y2);
}
3、画噪点
噪点和躁线原理一致,不过这里要使用的是Bitmap的SetPixel来完成,很简单也很好理解!
//画噪点
for (int i = 0; i < 100; i++)
{
int x = random.Next(codeW);
int y = random.Next(codeH);
Color color = colors[random.Next(colors.Length)];
bitmap.SetPixel(x, y, color);
}
4、画验证码
//画验证码
for (int i = 0; i < n; i++)
{
string fontStr = fonts[random.Next(fonts.Length)];
Font font = new Font(fontStr, fontSize);
Color color = colors[random.Next(colors.Length)];
graphics.DrawString(charCode[i].ToString(), font, new SolidBrush(color), (float)i * 15 + 2, (float)0);
}
//写入内存流
try
{
MemoryStream stream = new MemoryStream();
bitmap.Save(stream, ImageFormat.Jpeg);
VerifyCode verifyCode = new VerifyCode()
{
Code = charCode,
Image = stream.ToArray()
};
return verifyCode;
}
//释放资源
finally
{
graphics.Dispose();
bitmap.Dispose();
}
三、完整代码示例
上述是分布讲解图形验证码的生成过程,以及组成结构,这里提供完整的代码,以供大家参考和应用!一共三部分:验证码结构、枚举类型(NUM:数字验证码,CHAR字符验证码),工具类,并提供Web层调用代码!
public class VerifyCode
{
/// <summary>
/// 验证码
/// </summary>
public string Code {
get; set; }
/// <summary>
/// 验证码数据流
/// </summary>
public byte[] Image {
get; set; }
}
public enum VerifyCodeType
{
NUM,
CHAR
}
public static class VerifyCodeHelper
{
/// <summary>
/// 获取验证码
/// </summary>
/// <param name="n">验证码数</param>
/// <param name="type">类型 0:数字 1:字符</param>
/// <returns></returns>
public static VerifyCode CreateVerifyCode(int n, VerifyCodeType type)
{
//宽、高,字体大小
int codeW = 74;
int codeH = 36;
int fontSize = 16;
//初始化验证码
string charCode = string.Empty;
switch (type.ToString())
{
case "NUM":
charCode = CreateNumCode(n);
break;
default:
charCode = CreateCharCode(n);
break;
}
//颜色列表
Color[] colors = {
Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.DarkBlue };
//字体列表
string[] fonts = {
"Times New Roman", "Verdana", "Arial", "Gungsuh" };
//创建画布
Bitmap bitmap = new Bitmap(codeW, codeH);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.Clear(Color.White);
Random random = new Random();
//画躁线
for (int i = 0; i < n; i++)
{
int x1 = random.Next(codeW);
int y1 = random.Next(codeH);
int x2 = random.Next(codeW);
int y2 = random.Next(codeH);
Color color = colors[random.Next(colors.Length)];
Pen pen = new Pen(color);
graphics.DrawLine(pen, x1, y1, x2, y2);
}
//画噪点
for (int i = 0; i < 100; i++)
{
int x = random.Next(codeW);
int y = random.Next(codeH);
Color color = colors[random.Next(colors.Length)];
bitmap.SetPixel(x, y, color);
}
//画验证码
for (int i = 0; i < n; i++)
{
string fontStr = fonts[random.Next(fonts.Length)];
Font font = new Font(fontStr, fontSize);
Color color = colors[random.Next(colors.Length)];
graphics.DrawString(charCode[i].ToString(), font, new SolidBrush(color), (float)i * 15 + 2, (float)0);
}
//写入内存流
try
{
MemoryStream stream = new MemoryStream();
bitmap.Save(stream, ImageFormat.Jpeg);
VerifyCode verifyCode = new VerifyCode()
{
Code = charCode,
Image = stream.ToArray()
};
return verifyCode;
}
//释放资源
finally
{
graphics.Dispose();
bitmap.Dispose();
}
}
/// <summary>
/// 获取数字验证码
/// </summary>
/// <param name="n">验证码数</param>
/// <returns></returns>
public static string CreateNumCode(int n)
{
char[] numChar = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
string charCode = string.Empty;
Random random = new Random();
for (int i = 0; i < n; i++)
{
charCode += numChar[random.Next(numChar.Length)];
}
return charCode;
}
/// <summary>
/// 获取字符验证码
/// </summary>
/// <param name="n">验证码数</param>
/// <returns></returns>
public static string CreateCharCode(int n)
{
char[] strChar = {
'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','0','1','2','3',
'4','5','6','7','8','9','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'};
string charCode = string.Empty;
Random random = new Random();
for (int i = 0; i < n; i++)
{
charCode += strChar[random.Next(strChar.Length)];
}
return charCode;
}
}
public class VerifyCodeController : Controller
{
public async Task<FileResult> GetVerifyCode()
{
var oldVerifyCode = HttpContext.Session.GetString("VerifyCode");
if (!string.IsNullOrEmpty(oldVerifyCode))
{
HttpContext.Session.SetString("VerifyCode", "");
}
return await Task.Factory.StartNew(() =>
{
VerifyCode verifyCode = VerifyCodeHelper.CreateVerifyCode(4, VerifyCodeType.CHAR);
HttpContext.Session.SetString("VerifyCode", verifyCode.Code);
return File(verifyCode.Image, @"image/jpeg"); ;
});
}
}
<img src="/VerifyCode/GetVerifyCode" onclick="this.src=this.src+'?'"/>