一、生成随机字符串
方法一:
public string CreateRandomCode(int codeCount) { string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,a,b,c,d,e,f,g,h,i,g,k,l,m,n,o,p,q,r,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,s,t,u,v,w,x,y,z"; string[] allCharArray = allChar.Split(','); string randomCode = ""; //声明随机字符串变量 int temp = -1; Random rand = new Random(); //声明随机数对象 for (int i = 0; i < codeCount; i++) { if (temp != -1) { rand = new Random(i * temp * ((int)DateTime.Now.Ticks)); } int t = rand.Next(35); if (temp == t) { return CreateRandomCode(codeCount); } temp = t; randomCode += allCharArray[t]; } return randomCode; }
方法二:
private static string GetRandomString(int length) { return Guid.NewGuid().ToString("N").Substring((32 - length), length); }
二、创建验证码图片
实现方法一:
public byte[] CreateValidateGraphic(string validateCode) { //声明用于处理由像素数据定义的图像的对象(宽,高) Bitmap image = new Bitmap((int)Math.Ceiling(validateCode.Length * 16.0), 27); Graphics g = Graphics.FromImage(image); try { Random random = new Random(); g.Clear(Color.White); //清空图片背景色 //画图片的干扰线 for (int i = 0; i < 25; 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", 14, (FontStyle.Bold | FontStyle.Italic)); //设置字体样式和大小 LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2f, true); g.DrawString(validateCode, font, brush, 3, 2); //绘制指定的字符串 //画图片的前景干扰线 for (int i = 0; i < 100; 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), 0, 0, image.Width - 1, image.Height - 1); //画图片的边框线 //保存图片数据 MemoryStream stream = new MemoryStream(); image.Save(stream, ImageFormat.Jpeg); //输出图片流 return stream.ToArray(); } finally { g.Dispose(); image.Dispose(); } }
实现方法二:
/// <summary> /// 由随机字符串,随即颜色背景,和随机线条产生的Image /// </summary> /// <returns>Image</returns> public static byte[] GetVcodeImg(string text, int width = 200, int height = 45, int fontSize = 20) //返回 Image { int charNum = text.Length; //声明一个位图对象 Bitmap bitMap = null; //声明一个绘图画面 Graphics gph = null; //创建内存流 MemoryStream memStream = new MemoryStream(); Random random = new Random(); //由给定的需要生成字符串中字符个数 CharNum, 图片宽度 Width 和高度 Height 确定字号 FontSize, //确保不因字号过大而不能全部显示在图片上 int fontWidth = (int)Math.Round(width / (charNum + 2) / 1.3); int fontHeight = (int)Math.Round(height / 1.5); //字号取二者中小者,以确保所有字符能够显示,并且字符的下半部分也能显示 fontSize = fontWidth <= fontHeight ? fontWidth : fontHeight; //创建位图对象 bitMap = new Bitmap(width + fontSize, height); //根据上面创建的位图对象创建绘图图面 gph = Graphics.FromImage(bitMap); //设定验证码图片背景色 gph.Clear(GetControllableColor(200)); //产生随机干扰线条 for (int i = 0; i < 10; i++) { Pen backPen = new Pen(GetControllableColor(100), 2); //线条起点 int x = random.Next(width); int y = random.Next(height); //线条终点 int x2 = random.Next(width); int y2 = random.Next(height); //划线 gph.DrawLine(backPen, x, y, x2, y2); } //定义一个含10种字体的数组 String[] fontFamily = { "Arial", "Verdana", "Comic Sans MS", "Impact", "Haettenschweiler", "Lucida Sans Unicode", "Garamond", "Courier New", "Book Antiqua", "Arial Narrow" }; SolidBrush sb = new SolidBrush(GetControllableColor(0)); //通过循环,绘制每个字符, for (int i = 0; i < text.Length; i++) { Font textFont = new Font(fontFamily[random.Next(10)], fontSize, FontStyle.Bold); //字体随机,字号大小30,加粗 //每次循环绘制一个字符,设置字体格式,画笔颜色,字符相对画布的X坐标,字符相对画布的Y坐标 int space = (int)Math.Round((double)((width - fontSize * (charNum + 2)) / charNum)); //纵坐标 int y = (int)Math.Round((double)((height - fontSize) / 3)); gph.DrawString(text.Substring(i, 1), textFont, sb, fontSize + i * (fontSize + space), y); } //扭曲图片 bitMap = TwistImage(bitMap, true, random.Next(3, 5), random.Next(3)); bitMap.Save(memStream, ImageFormat.Gif); bitMap.Dispose(); return memStream.ToArray(); } /// <summary> /// 产生一种 R,G,B 均大于 colorBase 随机颜色,以确保颜色不会过深 /// </summary> /// <returns>背景色</returns> private static Color GetControllableColor(int colorBase) { Color color = Color.Black; Random random = new Random(); //确保 R,G,B 均大于 colorBase,这样才能保证背景色较浅 color = Color.FromArgb(random.Next(56) + colorBase, random.Next(56) + colorBase, random.Next(56) + colorBase); return color; } /// <summary> /// 扭曲图片 /// </summary> /// <param name="srcBmp"></param> /// <param name="bXDir"></param> /// <param name="dMultValue"></param> /// <param name="dPhase"></param> /// <returns></returns> private static Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase) { int leftMargin = 0; int rightMargin = 0; int topMargin = 0; int bottomMargin = 0; float PI2 = 6.28318530717959f; Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height); double dBaseAxisLen = bXDir ? Convert.ToDouble(destBmp.Height) : Convert.ToDouble(destBmp.Width); for (int i = 0; i < destBmp.Width; i++) { for (int j = 0; j < destBmp.Height; j++) { double dx = 0; dx = bXDir ? PI2 * Convert.ToDouble(j) / dBaseAxisLen : PI2 * Convert.ToDouble(i) / dBaseAxisLen; dx += dPhase; double dy = Math.Sin(dx); //取得当前点的颜色 int nOldX = 0; int nOldY = 0; nOldX = bXDir ? i + Convert.ToInt32(dy * dMultValue) : i; nOldY = bXDir ? j : j + Convert.ToInt32(dy * dMultValue); var color = srcBmp.GetPixel(i, j); if (nOldX >= leftMargin && nOldX < destBmp.Width - rightMargin && nOldY >= bottomMargin && nOldY < destBmp.Height - topMargin) { destBmp.SetPixel(nOldX, nOldY, color); } } } return destBmp; }
三、将 8位字节数组 转换为 base64字符串 类型的数据
private String BytesToBase64(Byte[] bytes) { try { return Convert.ToBase64String(bytes); } catch { return null; } }
四、接口与调用
本例是在网站中通过 ashx 文件写的
调用以上三个方法:
public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; StrHelper sh = new StrHelper(context); //自己写的类,这里用来返回json数据 string code = CreateRandomCode(4); //验证码的字符为4个 string image = BytesToBase64(CreateValidateGraphic(code)); //将图片验证码用base64类型的字符串返回(便于前端显示) sh.RebackJson(new { status = 200, code = code, image = image, type = "image/Jpeg" }); }
在页面中调用:
<a > <img id="img1" src="" onclick="changeImage()"/> </a> <script src="~/Scripts/jquery-1.10.2.js"></script> <script> window.onload = function () { changeImage(); } function changeImage() { $.ajax({ url: "http://服务器地址:端口号/SecurityCode.ashx", type: "post", success: function (data) { data = JSON.parse(data); console.log(data); $("#img1").attr("src", 'data:image/png;base64,' + data.image); }, error: function (data) { }, }) } </script>
实现方式二 -- 存储到 Redis 缓存中
/// <summary> /// 生成验证码 /// </summary> /// <returns></returns> public static async Task<VCode_Return> GetCodeAsync() { //生成数字并保存,将和图片的base64返回 var text = GetRandomString(4); string vid = ObjectId.GenerateNewId().ToString(); //存储缓存 await Redis.TopOauth.StringSetAsync($"VCODE:{vid}", text.ToLower(), new TimeSpan(0, 3, 0)); var bytes = GetVcodeImg(text); //生成图片 string imgbase64 = Convert.ToBase64String(bytes); //返回验证码 VCode_Return myReturn = new VCode_Return { vcode_image = imgbase64, vcodeid = vid }; return myReturn; }
1