如果說要做驗證碼,那不得不提的就是GDI+繪圖了。我們都知道驗證碼是以圖檔形式展示的,而且是動态生成的,這樣就需要我們去畫出它。
科普一下,什麼是GDI+?
GDI+是圖形裝置接口(GDI)的進階版本, 提供了各種豐富的圖形圖像處理功能。GDI+主要由二維矢量圖形、圖像處理和版式3部分組成。GDI+為使用各種字型、字号和樣式來顯示文本這種複雜任務提供了大量的支援。
下面說說驗證碼,對于驗證碼這樣的圖檔,我覺得是由兩部分組成的,一部分是矩形的背景,另一部分是在其上的字母數字組合(有的時候有漢字,有的時候是純字母或者純數字,這個沒有統一規定,怎麼選擇看你~)。對于矩形的背景我們可以直接把其當成畫布,字母數字組合呢?我們可以利用随機數去拼出一組新組合。這樣整個過程我們都想好了,下面看下代碼吧:
聲明一下,我寫的這個驗證碼為5個字元長度,由大小寫英文字母+數字随機組合。
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
<code> </code><code>private</code> <code>readonly</code> <code>char</code><code>[] constant = { </code>
<code> </code><code>'0'</code><code>,</code><code>'1'</code><code>,</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>'7'</code><code>,</code><code>'8'</code><code>,</code><code>'9'</code><code>, </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>'i'</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>'o'</code><code>,</code><code>'p'</code><code>,</code><code>'q'</code><code>,</code><code>'r'</code><code>,</code><code>'s'</code><code>,</code><code>'t'</code><code>,</code><code>'u'</code><code>,</code><code>'v'</code><code>,</code><code>'w'</code><code>,</code><code>'x'</code><code>,</code><code>'y'</code><code>,</code><code>'z'</code><code>, </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>'I'</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>'O'</code><code>,</code><code>'P'</code><code>,</code><code>'Q'</code><code>,</code><code>'R'</code><code>,</code><code>'S'</code><code>,</code><code>'T'</code><code>,</code><code>'U'</code><code>,</code><code>'V'</code><code>,</code><code>'W'</code><code>,</code><code>'X'</code><code>,</code><code>'Y'</code><code>,</code><code>'Z'</code><code>};</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>{</code>
<code> </code><code>Bitmap bitmap = </code><code>new</code> <code>Bitmap(100, 25);</code><code>//建立一個位圖,寬100,高25,就是我所說的第一部分,矩形背景</code>
<code> </code><code>Graphics g = Graphics.FromImage(bitmap);</code><code>//建立畫布</code>
<code> </code><code>g.Clear(Color.YellowGreen);</code><code>//為畫布填充黃綠色</code>
<code> </code><code>Font font1 = </code><code>new</code> <code>Font(</code><code>"Arial"</code><code>, 15);</code><code>//設定字型類型和大小 </code>
<code> </code><code>Brush brush = </code><code>new</code> <code>SolidBrush(Color.Blue);</code><code>//設定畫刷顔色</code>
<code> </code><code>Pen myPen = </code><code>new</code> <code>Pen(Color.Blue, 5);</code><code>//建立畫筆對象</code>
<code> </code><code>StringBuilder random = </code><code>new</code> <code>StringBuilder(5); </code><code>//建立可變字元串對象,用于存放随機生成的驗證碼</code>
<code> </code><code>Random rd = </code><code>new</code> <code>Random();</code><code>//建立一個随機數生成器對象</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i = 0; i < random.Capacity; i++)</code>
<code> </code><code>{</code>
<code> </code><code>random.Append(constant[rd.Next(62)]);</code><code>//生成一個随機字元加到random裡</code>
<code> </code><code>}</code>
<code> </code><code>g.DrawString(random.ToString(), font1, brush, 10, 5);</code><code>//在畫布上畫出字元串</code>
<code> </code><code>System.IO.MemoryStream ms = </code><code>new</code> <code>System.IO.MemoryStream();</code><code>//建立資料流MemoryStream</code>
<code> </code><code>bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);</code><code>//指定圖像的輸出格式為gif</code>
<code> </code><code>Response.ClearContent();</code>
<code> </code><code>Response.ContentType = </code><code>"image/Gif"</code><code>;</code>
<code> </code><code>Response.BinaryWrite(ms.ToArray());</code><code>//輸出二進制資料流</code>
<code> </code><code>}</code>
生成的效果是這樣的:
大家可能會覺得這樣看起來很容易辨識,跟我們平時登入網站時輸入的驗證碼比起來有點像個國小生。當然,我們可以做些改變,比較加上一定的角度。
32
33
34
35
36
37
38
<code> </code><code>float</code> <code>angle = 60;</code><code>//旋轉的一個基礎角度</code>
<code> </code><code>float</code> <code>length = 0;</code><code>//顯示字元的基礎位置,往後看</code>
<code> </code><code>g.ResetTransform();</code><code>//将畫布重置矩陣</code>
<code> </code><code>SizeF size = g.MeasureString(random[random.Length - 1].ToString(), font1);</code><code>//得到新生成字元的尺寸</code>
<code> </code><code>g.TranslateTransform(length + size.Width / 2, size.Height / 2);</code><code>//選擇此次旋轉的中心位置</code>
<code> </code><code>g.RotateTransform((</code><code>float</code><code>)rd.NextDouble() * angle * 2 - angle);</code><code>//進行随機角度旋轉</code>
<code> </code><code>g.DrawString(random[random.Length - 1].ToString(), font1, brush, </code><code>new</code> <code>PointF(-size.Width / 2, -size.Height / 2));</code><code>//注意,這裡不是前一個例子,一次性把5個字元全部畫出來,而是一個一個畫</code>
<code> </code><code>length += size.Width;</code><code>//保證下次畫字元的位置不會覆寫前一次的字元</code>
這時生成的效果是這樣的:
是不是看起來更專業一些了呢?如果大家還是覺得不滿意的話,可以看下GDI+的相關内容,通過添加一些噪點的元素,或者删除線這樣子的東西來達到提高識别難度的目的,我這裡就不一一列舉啦。
關于如何畫驗證碼我們說過了,但是還有兩點問題我還是想多說一下。
1、我們實際輸出的是一個二進制的流,如何做到顯示到頁面上與頁面其他元素共存呢?
這裡通用的一種方法就是把畫驗證碼的這段代碼放到一個獨立的Web窗體頁中,在另一個需要顯示驗證碼的頁面放一個<img>元素,把其src屬性指向該驗證碼頁的url。比如我寫的一段是這樣
<code><asp:Image ID=</code><code>"image_validatecode"</code> <code>runat=</code><code>"server"</code> <code>ImageUrl=</code><code>"~/PublicMethod/ValidateCode.aspx"</code> <code>style=</code><code>"padding-left:3px"</code><code>/></code>
其實這裡我是用大家通用的方法,不過我先前也有單獨寫一個web自定義控件,專門生成驗證碼使用,但是當拖入到頁面中後運作,它還是會把頁面其他元素給覆寫掉,具體原因我也不清楚。
2、驗證碼主要目的還是用于驗證使用的,是以我們在使用者名,密碼是否合法外,同時也要判斷目前輸入的驗證碼是不是與圖檔上的驗證碼一緻。
我上面的代碼中并沒有寫這塊,其實隻要在随機生成最終驗證碼之後,把其值存入一個session中去就可以了。然後在判斷使用者名,密碼的同時去比較一下這個session值就OK了。如:
<code>Session[</code><code>"login_validate_code"</code><code>] = random.ToString();</code>
3、如何使用者沒有看清此張驗證碼,想換一張如何實作?
可以通過腳本給img元素的src屬性重新指派url實作,當然,麻煩點的話也可以使用ajax去實作。大家可以自己試試。
本文轉自 我不會抽煙 51CTO部落格,原文連結:http://blog.51cto.com/zhouhongyu1989/1532047,如需轉載請自行聯系原作者