接續上一篇的簡介,我們這一次實作一個簡易的 ASP.NET 的圖現驗證。
步驟1: 顯示圖形
一般來說,圖形只能給人工來閱讀,SpamRobot 碰到圖形當然較吃力。這個步驟,我們就先把文字變成最簡單的圖形吧。
using System; using System.Drawing; using System.Drawing.Imaging; using System.Drawing.Text; using System.Web.UI; namespace Captcha { public partial class Sample1 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { CreateImage("I wanna go home"); } image.ImageUrl = ImageUrl; } //圖檔放置的位置 private string ImagePath { get { return Server.MapPath(ImageUrl); } } //圖檔的 Url。使用 SessionID 避免重複 private string ImageUrl { get { return "~/imgs/" + Session.SessionID + ".gif"; } } private void CreateImage(string imageText) { //建立一個 Bitmap。寬高未定,故先給定1, 1 Bitmap bmpImage = new Bitmap(1, 1); //指定字型 Font font = new Font("Verdana", 24, FontStyle.Bold, GraphicsUnit.Point); //進行繪圖。繪圖需透過 Grahpics 物件。 Graphics graphics = Graphics.FromImage(bmpImage); //測量文字的寬高 int width = (int)graphics.MeasureString(imageText, font).Width; int height = (int)graphics.MeasureString(imageText, font).Height; //重新指定 Bitmap bmpImage = new Bitmap(bmpImage, new Size(width, height)); //重新繪圖 graphics = Graphics.FromImage(bmpImage); graphics.Clear(Color.White); //使用白底 graphics.TextRenderingHint = TextRenderingHint.AntiAlias; //不要鋸齒 graphics.DrawString(imageText, font, new SolidBrush(Color.Red), 0, 0); //把文字畫上去 graphics.Flush(); bmpImage.Save(ImagePath, ImageFormat.Gif); //記得 release 記憶體 graphics.Dispose(); font.Dispose(); bmpImage.Dispose(); } } }
而網頁使用了簡單的 asp:image
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Sample1.aspx.cs" Inherits="Captcha.Sample1" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> <div> <asp:Image runat="server" ID="image" /> </div> </form> </body> </html>
在步驟1中,我使用了 Session 作為圖檔的名稱,儲存在網站的目錄下,並以 asp:image 來顯示圖形。
步驟2: 亂數
上一個步驟中,驗證的文字是寫固定地。這個步驟我們就來亂一下吧!
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { string randomString = GetRandomString(4); CreateImage(randomString); } image.ImageUrl = ImageUrl; } private string GetRandomString(int length) { char[] chars = @"2346789ABCDEFGHIJKLMNPQRTUVWXYZ".ToCharArray(); Random r = new Random((int)DateTime.Now.Ticks); StringBuilder sb = new StringBuilder(length); for (int i = 0; i < length; i++) sb.Append(chars[r.Next(chars.Length)]); return sb.ToString(); }
顯示的文字,不能讓使用者不小心看錯,例如O 與 0,l, i, 與 1,S與5。為了易於使用,必須將這些容易誤解的字元全部移掉。圖形如下
步驟3: 驗證
這是最簡單的步驟了。將驗證用的文字儲存起來,放到 Session中,等待使用者的回應並檢查之。
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { VerifyNow(); } } private void VerifyNow() { string randomString = GetRandomString(4); Session["ImgText"] = randomString; CreateImage(randomString); image.ImageUrl = ImageUrl; } protected void btnSubmit_Click(object sender, EventArgs e) { string randomString = Session["ImgText"] as string; if (randomString != txtAnswer.Text.Trim()) { Response.Write("驗證錯誤"); VerifyNow(); //重新產生驗證文字 } else Response.Write("驗證成功"); }
結論
這是一個極簡單的CAPTCHA圖形驗證的範例。雖然已經可以運作了,但仍然有不少的缺點,例如可重用性,使用了Session,以及最重要的是「圖形太簡單」的問題。
由於道高一尺魔高一丈的布袋戲真理,一定有 AntiCaptcha 工具的產生,圖形太過於簡單,等同於不設防。另外驗證文字的長度也太短了些,10000次總有一次會猜中,也是個問題。
範例可在這裡下載
沒有留言:
張貼留言