前言:
昨天思路错误,白忙了一上午因为Exchange安装好之后是依附于IIS的所以我们看到登陆界面也是个.aspx页面 通过IIS找到的Exchange安装目录发现只有logon.aspx页面 没有也不可能有logon.aspx.cs页面,说白了就是微软给咱们写好了一个(一套)软件--Exchange邮件服务系统,对于用户,亲你只需要安装就行了。。。
后语:
这意味着exchange走的也是IIS,也是asp.net那一套流程,ok 需求来了:
上帝:我想要在邮箱登陆的时候加一个验证码的功能,这样不是会更安全嘛。
开发者:额,好吧。。。(心说,尼玛坑爹呐,这是微软写好的我怎么给你加验证码呀!!)
儿子就算是在坑爹,那也是咱儿子啊,满足不了他到时候认贼作父就不好了。
说了半天废话咱们奔主题吧。。。。。。。。
主题:
既然我们能看到Exchange安装好部署后的页面能对于前端来讲我们还是可以改变的,思路有一下3种:
1)网上案例:
2)前端验证
顾名思义,就是使用js来在前端动态生成验证功能,控制用户登录
缺点:这只是表面的现象,一旦有高手察觉这个验证功能只是张纸那么薄,很容易捅破。
demo:效果如下
<a target="_blank" href="http://blog.51cto.com/attachment/201309/133947902.png"></a>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<code><</code><code>html</code> <code>xmlns</code><code>=</code><code>"http://www.w3.org/1999/xhtml"</code> <code>></code>
<code><</code><code>head</code><code>></code>
<code> </code><code><</code><code>title</code><code>>无标题页</</code><code>title</code><code>></code>
<code> </code><code><</code><code>style</code> <code>type</code><code>=</code><code>"text/css"</code><code>></code>
<code> </code><code>.code</code>
<code> </code><code>{</code>
<code> </code><code>background-image:url(code.jpg);</code>
<code> </code><code>font-family:Arial;</code>
<code> </code><code>font-style:italic;</code>
<code> </code><code>color:Red;</code>
<code> </code><code>border:0;</code>
<code> </code><code>padding:2px 3px;</code>
<code> </code><code>letter-spacing:3px;</code>
<code> </code><code>font-weight:bolder;</code>
<code> </code><code>}</code>
<code> </code><code>.unchanged</code>
<code> </code><code></</code><code>style</code><code>></code>
<code> </code><code><</code><code>script</code> <code>language</code><code>=</code><code>"javascript"</code> <code>type</code><code>=</code><code>"text/javascript"</code><code>></code>
<code> </code><code>var code; //在全局 定义验证码</code>
<code> </code><code>function createCode() {</code>
<code> </code><code>code = "";</code>
<code> </code><code>var codeLength = 6;//验证码的长度</code>
<code> </code><code>var checkCode = document.getElementById("checkCode");</code>
<code> </code><code>var selectChar = new Array(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');//所有候选组成验证码的字符,当然也可以用中文的</code>
<code> </code><code>for (var i = 0; i < </code><code>codeLength</code><code>; i++) {</code>
<code> </code><code>var </code><code>charIndex</code> <code>= </code><code>Math</code><code>.floor(Math.random() * 36);</code>
<code> </code><code>code += selectChar[charIndex];</code>
<code> </code><code>}</code>
<code> </code><code>// alert(code);</code>
<code> </code><code>if (checkCode) {</code>
<code> </code><code>checkCode.className</code> <code>= </code><code>"code"</code><code>;</code>
<code> </code><code>checkCode.value</code> <code>= </code><code>code</code><code>;</code>
<code> </code><code>function validate() {</code>
<code> </code><code>var </code><code>inputCode</code> <code>= </code><code>document</code><code>.getElementById("input1").value;</code>
<code> </code><code>if (inputCode.length <= 0) {</code>
<code> </code><code>alert("请输入验证码!");</code>
<code> </code><code>else if (inputCode.toUpperCase() != code.toUpperCase()) {</code>
<code> </code><code>alert("验证码输入错误!");</code>
<code> </code><code>createCode();//刷新验证码</code>
<code> </code><code>else {</code>
<code> </code><code>alert("^-^ OK");</code>
<code> </code><code></script></code>
<code></</code><code>head</code><code>></code>
<code><</code><code>body</code> <code><form </code><code>action</code><code>=</code><code>"#"</code><code>></code>
<code> </code><code><</code><code>table</code><code>></code>
<code> </code><code><</code><code>tr</code><code>><</code><code>td</code><code>>姓 名:</</code><code>td</code><code>><</code><code>td</code><code>><</code><code>input</code> <code>type</code><code>=</code><code>"text"</code> <code>style</code><code>=</code><code>"width: 160px;"</code><code>/></</code><code>td</code><code>></</code><code>tr</code><code>></code>
<code> </code><code><</code><code>tr</code><code>><</code><code>td</code><code>>密 码:</</code><code>td</code><code>><</code><code>td</code><code>><</code><code>input</code> <code>type</code><code>=</code><code>"password"</code> <code>style</code><code>=</code><code>"width: 160px;"</code><code>/></</code><code>td</code><code>></</code><code>tr</code><code>></code>
<code> </code><code><</code><code>tr</code><code>><</code><code>td</code><code>>验证码:</</code><code>td</code><code>><</code><code>td</code><code>><</code><code>input</code> <code>type</code><code>=</code><code>"text"</code> <code>style</code><code>=</code><code>"width: 160px;"</code> <code>id</code><code>=</code><code>"input1"</code> <code>/></code>
<code> </code><code><</code><code>input</code> <code>type</code><code>=</code><code>"text"</code> <code>readonly</code><code>=</code><code>"readonly"</code> <code>id</code><code>=</code><code>"checkCode"</code> <code>class</code><code>=</code><code>"unchanged"</code> <code>style</code><code>=</code><code>"width: 80px"</code> <code>/></</code><code>td</code><code>></</code><code>tr</code><code>></code>
<code> </code><code><</code><code>tr</code><code>><</code><code>td</code><code>></</code><code>td</code><code>><</code><code>td</code><code>><</code><code>input</code> <code>id</code><code>=</code><code>"Button1"</code> <code>type</code><code>=</code><code>"button"</code> <code>value</code><code>=</code><code>"确定"</code> <code>/> </</code><code>td</code><code>></</code><code>tr</code><code>></code>
<code> </code><code></</code><code>table</code><code>></code>
<code> </code>
<code> </code><code></</code><code>form</code><code>></code>
<code></</code><code>body</code><code>></code>
<code></</code><code>html</code><code>></code>
亲你懂了吧~~~~~~~
3)后端伪验证:
哎,为什么要加个“伪”呐因为如果不是js你也没办法阻止表单的提交,而且表单提交后也没有什么验证,就是在验证用户登录的时候你是没办法拦截用户的登录信息提取验证码的
缺点:类似前端js 验证
demo:先上效果图:
<a target="_blank" href="http://blog.51cto.com/attachment/201309/135115470.png"></a>
废话不多说了,贴出流程:
在IIS中找到Exchange登录界面页面的物理路径,找到页面logon.aspx,添加如下代码:
<code><!----------------------------------------------------------- start 验证码 ---------------------------------------------------------------------></code>
<code><</code><code>tr</code><code>><</code><code>td</code> <code>nowrap><</code><code>label</code> <code>for</code><code>=</code><code>"yzm"</code><code>>验证码:</</code><code>label</code><code>></</code><code>td</code><code>><</code><code>td</code> <code>class</code><code>=</code><code>"txtpad"</code><code>><</code><code>input</code> <code>type</code><code>=</code><code>'text'</code> <code>class</code><code>=</code><code>'txt'</code> <code>maxlength</code><code>=</code><code>"4"</code> <code>style</code><code>=</code><code>"width:220px;"</code> <code>id</code><code>=</code><code>'yzm'</code> <code>/></code>
<code><</code><code>img</code> <code>src</code><code>=</code><code>'GetImg.aspx'</code> <code>alt</code><code>=</code><code>"点击切换验证码"</code> <code>title</code><code>=</code><code>"点击切换验证码"</code> <code>style</code><code>=</code><code>" margin-top:2px; vertical-align:top;cursor:pointer;"</code> <code>'GetImg.aspx');return false;" /></</code><code>td</code><code>></code>
<code></</code><code>tr</code><code>></code>
<code> </code><code><!----------------------------------------------------------- end 验证码 ---------------------------------------------------------------------></code>
你懂得,具体位置有你定,然后加入以下js代码(这个位置随意):
<code><!------------------------------------------ 验证码 脚本 ------------------------------------------------------------></code>
<code><script type=</code><code>"text/javascript"</code> <code>src=</code><code>"jquery-1.7.1.min.js"</code><code>></script></code>
<code><script type=</code><code>"text/javascript"</code><code>></code>
<code>function</code> <code>ToggleCode(obj, codeurl) {</code>
<code> </code><code>$(obj).attr(</code><code>"src"</code><code>, codeurl + </code><code>"?time="</code> <code>+ Math.random());</code>
<code>}</code>
<code>var</code> <code>bo=</code><code>false</code><code>;</code>
<code>$(document).ready(</code><code>function</code><code>(){</code>
<code> </code><code>$(</code><code>".btn"</code><code>).before(</code><code>"<label id='spanMsg' style='color:red;padding-right:50px;'> </label>"</code><code>);</code>
<code> </code><code>$(</code><code>".btn"</code><code>).click(</code><code>function</code><code>(){</code>
<code> </code><code>if</code><code>(bo){</code>
<code> </code><code>return</code> <code>true</code><code>;</code>
<code> </code><code>}</code><code>else</code><code>{</code>
<code> </code><code>var</code> <code>codeVaule=$(</code><code>"#yzm"</code><code>).val();</code>
<code> </code><code>if</code><code>(codeVaule==</code><code>""</code><code>){</code>
<code> </code><code>$(</code><code>"#spanMsg"</code><code>).html(</code><code>"*验证码不能为空!"</code><code>);</code>
<code> </code><code>return</code> <code>false</code><code>;</code>
<code> </code><code>}</code><code>else</code> <code>if</code><code>(codeVaule.length!=4){</code>
<code> </code><code>$(</code><code>"#spanMsg"</code><code>).html(</code><code>"*验证码位数不够!"</code><code>);</code>
<code> </code><code>}</code><code>else</code><code>{</code>
<code> </code><code>$.get(</code><code>"VerifyCode.aspx?yzmc="</code><code>+codeVaule,{},</code><code>function</code><code>(data){</code>
<code> </code><code>if</code><code>(data==</code><code>"ok"</code><code>){</code>
<code> </code><code>$(</code><code>"#spanMsg"</code><code>).html(</code><code>"*验证码正确!"</code><code>);</code>
<code> </code><code>$(</code><code>".btn"</code><code>).click();</code>
<code> </code><code>bo=</code><code>true</code><code>;</code>
<code> </code><code>}</code><code>else</code><code>{</code>
<code> </code><code>$(</code><code>"#spanMsg"</code><code>).html(</code><code>"*验证码错误!"</code><code>);</code>
<code> </code><code>}</code>
<code> </code><code>});</code>
<code> </code><code>return</code> <code>bo;</code>
<code> </code>
<code> </code><code>});</code>
<code>});</code>
<code></script></code>
<code><!------------------------------------------- end 验证码 脚本 -----------------------------------------------------------></code>
然后在logon.aspx同一目录下添加jquery-1.7.1.min.js文件具体是什么版本的jquery你可以任意选择,应该都能兼容。注意js代码的引用名称一致。然后添加GetImg.aspx文件代码如下:
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
<code><%@ Page Language=</code><code>"C#"</code> <code>AutoEventWireup=</code><code>"true"</code> <code>%></code>
<code><%@ Import Namespace=</code><code>"System.Drawing"</code> <code>%></code>
<code><%@ Import Namespace=</code><code>"System.Drawing.Imaging"</code> <code>%></code>
<code><%@ Import Namespace=</code><code>"System.IO"</code> <code>%></code>
<code><%@ Import Namespace=</code><code>"System.Security.Cryptography"</code> <code>%></code>
<code><script runat=</code><code>"server"</code><code>></code>
<code> </code><code>public</code> <code>static</code> <code>string Encrypt(string Text)</code>
<code> </code><code>{</code>
<code> </code><code>string sKey = </code><code>"nysoftland.com.cn"</code><code>;</code>
<code> </code><code>DESCryptoServiceProvider des = </code><code>new</code> <code>DESCryptoServiceProvider();</code>
<code> </code><code>byte[] inputByteArray;</code>
<code> </code><code>inputByteArray = Encoding.Default.GetBytes(Text);</code>
<code> </code><code>des.Key = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, </code><code>"md5"</code><code>).Substring(</code><code>0</code><code>, </code><code>8</code><code>));</code>
<code> </code><code>des.IV = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, </code><code>"md5"</code><code>).Substring(</code><code>0</code><code>, </code><code>8</code><code>));</code>
<code> </code><code>System.IO.MemoryStream ms = </code><code>new</code> <code>System.IO.MemoryStream();</code>
<code> </code><code>CryptoStream cs = </code><code>new</code> <code>CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);</code>
<code> </code><code>cs.Write(inputByteArray, </code><code>0</code><code>, inputByteArray.Length);</code>
<code> </code><code>cs.FlushFinalBlock();</code>
<code> </code><code>StringBuilder ret = </code><code>new</code> <code>StringBuilder();</code>
<code> </code><code>foreach (byte b </code><code>in</code> <code>ms.ToArray())</code>
<code> </code><code>ret.AppendFormat(</code><code>"{0:X2}"</code><code>, b);</code>
<code> </code><code>return</code> <code>ret.ToString();</code>
<code> </code><code>}</code>
<code> </code><code>public</code> <code>static</code> <code>string Decrypt(string Text)</code>
<code> </code><code>string sKey = </code><code>"Exchange"</code><code>;</code>
<code> </code><code>int</code> <code>len;</code>
<code> </code><code>len = Text.Length / </code><code>2</code><code>;</code>
<code> </code><code>byte[] inputByteArray = </code><code>new</code> <code>byte[len];</code>
<code> </code><code>int</code> <code>x, i;</code>
<code> </code><code>for</code> <code>(x = </code><code>0</code><code>; x < len; x++)</code>
<code> </code><code>i = Convert.ToInt32(Text.Substring(x * </code><code>2</code><code>, </code><code>2</code><code>), </code><code>16</code><code>);</code>
<code> </code><code>inputByteArray[x] = (byte)i;</code>
<code> </code><code>CryptoStream cs = </code><code>new</code> <code>CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);</code>
<code> </code><code>return</code> <code>Encoding.Default.GetString(ms.ToArray());</code>
<code> </code><code>protected</code> <code>void</code> <code>Page_Load(object sender, EventArgs e)</code>
<code> </code><code>int</code> <code>codeW = </code><code>80</code><code>;</code>
<code> </code><code>int</code> <code>codeH = </code><code>22</code><code>;</code>
<code> </code><code>int</code> <code>fontSize = </code><code>16</code><code>;</code>
<code> </code><code>string chkCode = string.Empty;</code>
<code> </code><code>Color[] color = { Color.Black, Color.Red, Color.Blue, Color.Green, Color.Orange, Color.Brown, Color.Brown, Color.DarkBlue };</code>
<code> </code><code>string[] font = { </code><code>"Times New Roman"</code><code>, </code><code>"Verdana"</code><code>, </code><code>"Arial"</code><code>, </code><code>"Gungsuh"</code><code>, </code><code>"Impact"</code> <code>};</code>
<code> </code><code>char[] character = { </code><code>'2'</code><code>, </code><code>'3'</code><code>, </code><code>'4'</code><code>, </code><code>'5'</code><code>, </code><code>'6'</code><code>, </code><code>'8'</code><code>, </code><code>'9'</code><code>, </code><code>'a'</code><code>, </code><code>'b'</code><code>, </code><code>'d'</code><code>, </code><code>'e'</code><code>, </code><code>'f'</code><code>, </code><code>'h'</code><code>, </code><code>'k'</code><code>, </code><code>'m'</code><code>, </code><code>'n'</code><code>, </code><code>'r'</code><code>, </code><code>'x'</code><code>, </code><code>'y'</code><code>, </code><code>'A'</code><code>, </code><code>'B'</code><code>, </code><code>'C'</code><code>, </code><code>'D'</code><code>, </code><code>'E'</code><code>, </code><code>'F'</code><code>, </code><code>'G'</code><code>, </code><code>'H'</code><code>, </code><code>'J'</code><code>, </code><code>'K'</code><code>, </code><code>'L'</code><code>, </code><code>'M'</code><code>, </code><code>'N'</code><code>, </code><code>'P'</code><code>, </code><code>'R'</code><code>, </code><code>'S'</code><code>, </code><code>'T'</code><code>, </code><code>'W'</code><code>, </code><code>'X'</code><code>, </code><code>'Y'</code> <code>};</code>
<code> </code><code>Random rnd = </code><code>new</code> <code>Random();</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i < </code><code>4</code><code>; i++)</code>
<code> </code><code>chkCode += character[rnd.Next(character.Length)];</code>
<code> </code><code>//Session["yzmCode"] = chkCode;</code>
<code> </code><code>HttpCookie cook = </code><code>new</code> <code>HttpCookie(</code><code>"yzmCode"</code><code>, Encrypt(chkCode));</code>
<code> </code><code>cook.Expires = DateTime.Now.AddMinutes(</code><code>20</code><code>);</code>
<code> </code><code>Response.Cookies.Add(cook);</code>
<code> </code><code>Bitmap bmp = </code><code>new</code> <code>Bitmap(codeW, codeH);</code>
<code> </code><code>Graphics g = Graphics.FromImage(bmp);</code>
<code> </code><code>g.Clear(Color.White);</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i < </code><code>1</code><code>; i++)</code>
<code> </code><code>int</code> <code>x1 = rnd.Next(codeW);</code>
<code> </code><code>int</code> <code>y1 = rnd.Next(codeH);</code>
<code> </code><code>int</code> <code>x2 = rnd.Next(codeW);</code>
<code> </code><code>int</code> <code>y2 = rnd.Next(codeH);</code>
<code> </code><code>Color clr = color[rnd.Next(color.Length)];</code>
<code> </code><code>g.DrawLine(</code><code>new</code> <code>Pen(clr), x1, y1, x2, y2);</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i < chkCode.Length; i++)</code>
<code> </code><code>string fnt = font[rnd.Next(font.Length)];</code>
<code> </code><code>Font ft = </code><code>new</code> <code>Font(fnt, fontSize);</code>
<code> </code><code>g.DrawString(chkCode[i].ToString(), ft, </code><code>new</code> <code>SolidBrush(clr), (float)i * </code><code>18</code> <code>+ </code><code>2</code><code>, (float)</code><code>0</code><code>);</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i < </code><code>100</code><code>; i++)</code>
<code> </code><code>int</code> <code>x = rnd.Next(bmp.Width);</code>
<code> </code><code>int</code> <code>y = rnd.Next(bmp.Height);</code>
<code> </code><code>bmp.SetPixel(x, y, clr);</code>
<code> </code><code>Response.Buffer = </code><code>true</code><code>;</code>
<code> </code><code>Response.ExpiresAbsolute = System.DateTime.Now.AddMilliseconds(</code><code>0</code><code>);</code>
<code> </code><code>Response.Expires = </code><code>0</code><code>;</code>
<code> </code><code>Response.CacheControl = </code><code>"no-cache"</code><code>;</code>
<code> </code><code>Response.AppendHeader(</code><code>"Pragma"</code><code>, </code><code>"No-Cache"</code><code>);</code>
<code> </code><code>MemoryStream ms = </code><code>new</code> <code>MemoryStream();</code>
<code> </code><code>try</code>
<code> </code><code>bmp.Save(ms, ImageFormat.Png);</code>
<code> </code><code>Response.ClearContent();</code>
<code> </code><code>Response.ContentType = </code><code>"image/Png"</code><code>;</code>
<code> </code><code>Response.BinaryWrite(ms.ToArray());</code>
<code> </code><code>finally</code>
<code> </code><code>bmp.Dispose();</code>
<code> </code><code>g.Dispose();</code>
在第72行的时候不适用session验证,因为Exchange安装后使用的不是Session验证机制,所以我们在73~75行采用Cookies验证机制。以上代码用于生成验证码。
下边采用jquery异步验证机制验证 验证码填写是否正确,同样添加VerifyCode.aspx文件代码如下:
<code><%@ Page Language=</code><code>"C#"</code> <code>AutoEventWireup=</code><code>"true"</code> <code>%></code>
<code> </code><code>protected</code> <code>void</code> <code>Page_Load(</code><code>object</code> <code>sender, EventArgs e)</code>
<code> </code><code>if</code> <code>(Request.Cookies[</code><code>"yzmCode"</code><code>] != </code><code>null</code><code>&&Request.QueryString[</code><code>"yzmc"</code><code>]!=</code><code>null</code><code>)</code>
<code> </code><code>string</code> <code>code = Decrypt(Request.Cookies[</code><code>"yzmCode"</code><code>].Value).ToUpper();</code>
<code> </code><code>string</code> <code>ucode = Request.QueryString[</code><code>"yzmc"</code><code>].ToUpper();</code>
<code> </code><code>if</code> <code>(code == ucode)</code>
<code> </code><code>{</code>
<code> </code><code>Response.Write(</code><code>"ok"</code><code>);</code>
<code> </code><code>Response.End();</code>
<code> </code><code>else</code>
<code> </code><code>Response.Write(</code><code>"error"</code><code>);</code>
<code> </code><code>else</code>
<code> </code><code>Response.Write(</code><code>"error2"</code><code>);</code>
<code> </code><code>Response.End();</code>
<code> </code><code>public</code> <code>static</code> <code>string</code> <code>Decrypt(</code><code>string</code> <code>Text)</code>
<code> </code><code>string</code> <code>sKey = </code><code>"Exchange"</code><code>;</code>
<code> </code><code>len = Text.Length / 2;</code>
<code> </code><code>byte</code><code>[] inputByteArray = </code><code>new</code> <code>byte</code><code>[len];</code>
<code> </code><code>for</code> <code>(x = 0; x < len; x++)</code>
<code> </code><code>i = Convert.ToInt32(Text.Substring(x * 2, 2), 16);</code>
<code> </code><code>inputByteArray[x] = (</code><code>byte</code><code>)i;</code>
<code> </code><code>des.Key = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, </code><code>"md5"</code><code>).Substring(0, 8));</code>
<code> </code><code>des.IV = ASCIIEncoding.ASCII.GetBytes(System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(sKey, </code><code>"md5"</code><code>).Substring(0, 8));</code>
<code> </code><code>cs.Write(inputByteArray, 0, inputByteArray.Length);</code>
到此我们的代码就已经填写完毕了
总结:
有很好的asp.net底层基础遇到问题还是能解决的挺顺手的。不过说白了这些都是表面现象,你无法重写Exchange编译好的dll,也就是说想绕过你的验证还是很容易的,这些都只是忽悠用户拔了,如果想更安全就要修改IIS,在Exchange登录时再包装一层是用户无法绕过验证码的验证,只不过本次需求不需要这么高的安全性,能用好看就行...
欢迎诸位大神拍砖。。。。
本文转自 tongling_zzu 51CTO博客,原文链接:http://blog.51cto.com/tongling/1295069