Các trang web hiện nay sử dụng captcha rất phổ biến để tránh tình trạng đăng kí hoặc đăng nhập tự động (không phải do người dùng tự thao tác) một cách tràn lan. Captch thường có dạng một hình ảnh hoặc đoạn flash chứa những kí tự ngẫu nhiên được làm biến dạng nhằm gây khó khăn cho các chương trình có khả năng nhận diện kí tự.
Trong bài viết này tôi sẽ hướng dẫn tạo chức năng captcha đơn giản bằng ASP.Net với ngôn ngữ là C#. Bạn cần có các khái niệm cơ bản về ASP.Net và cách sử dụng phương thức đồ họa GDI+ trong C# để hiểu rõ được phương pháp này.
Các namespace chính của GDI+ bạn cần sử dụng là:
System.Drawing
System.Drawing.Drawing2D
Đầu tiên bạn hãy tạo một WebSite ASP.Net, sử dụng sẵn trang Default.aspx để làm ví dụ này. Tạo các control giống như đoạn mã sau trong phần body của trang:
1 2 3 4 5 6 7 8 9 10 |
<form id="form1" runat="server"> <div> <asp:Image ID="imgCaptcha" runat="server" /> <asp:ImageButton ID="imbReLoad" runat="server" ImageUrl="~/Images/ajax-arrows-green.gif" OnClick="imbReLoad_Click" /><br /> <asp:TextBox runat="Server" ID="txtCaptcha" /> <br /> <asp:Button runat="Server" ID="btnSubmit" Text="Đồng" ý OnClick="btnSubmit_Click" /> <br /> <asp:Label ID="lblMessage" runat="server" ForeColor="Red"></asp:Label></div> </form> |
Giải thích công dụng các control:
– imgCaptcha: Image dùng để hiển thị hình ảnh captcha
– imbReload: ImageButton để thay đổi ảnh captcha
– txtCaptcha: TextBox để người dùng nhập chuỗi kí tự captcha
– btnSubmit: Button kiểm tra việc nhập liệu
– lblMessage: Label hiển thị thông báo sau khi người dùng nhấn nút Submit
Tiếp đến chúng ta cần tạo một phương thức để tạo ảnh captcha và hiển thị lên imgCaptcha, tôi đặt tên phương thức này là CreateCaptcha():
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 |
private void CreateCaptcha() { string[] fonts = { "Arial Black", "Lucida Sans Unicode", "Comic Sans MS" }; const byte LENGTH = 5; // chuỗi để lấy các kí tự sẽ sử dụng cho captcha const string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; using (Bitmap bmp = new Bitmap(120, 30)) { using (Graphics g = Graphics.FromImage(bmp)) { // Tạo nền cho ảnh dạng sóng HatchBrush brush = new HatchBrush(HatchStyle.Wave, Color.White, Color.Wheat); g.FillRegion(brush, g.Clip); // Lưu chuỗi captcha trong quá trình tạo StringBuilder strCaptcha = new StringBuilder(); Random rand = new Random(); for (int i = 0; i < LENGTH; i++) { // Lấy kí tự ngẫu nhiên từ mảng chars string str = chars[rand.Next(chars.Length)].ToString(); strCaptcha.Append(str); // Tạo font với tên font ngẫu nhiên chọn từ mảng fonts Font font = new Font(fonts[rand.Next(fonts.Length)], 12, FontStyle.Strikeout | FontStyle.Italic); // Lấy kích thước của kí tự SizeF size = g.MeasureString(str, font); // Vẽ kí tự đó ra ảnh tại vị trí tăng dần theo i, vị trí top ngẫu nhiên g.DrawString(str, font, Brushes.Chocolate, i * size.Width + 3, rand.Next(2, 10)); font.Dispose(); } // Lưu captcha vào session Session["captcha"] = strCaptcha.ToString(); // Lưu ảnh vào thư mục captcha với tên ảnh dựa theo IP string path = "Captcha/" + Request.UserHostAddress + ".gif"; bmp.Save(Server.MapPath("") + "/" + path, ImageFormat.Gif); imgCaptcha.ImageUrl = path; } } } |
(Đối tượng kiểu HatchBrush có rất nhiều kiểu vẽ cho bạn khá nhiều sự lựa chọn trong enum HatchStyle , bạn hãy thử tìm cho mình một style mà thích hợp để làm nền cho captcha.)
Sau đó hai viết tiếp mã lệnh cho các sự kiện sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) CreateCaptcha(); } protected void imbReLoad_Click(object sender, System.Web.UI.ImageClickEventArgs e) { CreateCaptcha(); } protected void btnSubmit_Click(object sender, EventArgs e) { if (txtCaptcha.Text.Equals(Session["captcha"].ToString(), StringComparison.OrdinalIgnoreCase)) lblMessage.Text = "Chuỗi xác nhận chính xác"; else lblMessage.Text = "Vui lòng nhập đúng chuỗi xác nhận"; } |
Bây giờ hãy chạy thử và kiểm tra xem chức năng này có hoạt động đúng không, giao diện trang web như sau:
captcha
Rất đơn giản phải không, tuy nhiên cách này có một số hạn chế như việc lưu tập tin ảnh quá nhiều vào thư mục captcha của server có thể gây lãng phí nhiều tài nguyên. Việc đọc ghi dữ liệu từ ổ cứng làm chậm tốc độ xử lý và các ảnh captcha vẫn được lưu lại trong thư mục nếu không xóa đi định kì.
Để giải quyết cho vấn đề này, chúng ta sẽ sử dụng kĩ thuật ghi trực tiếp ảnh ra đối tượng imgCaptcha thông qua luồng xuất đến máy khách.
Bây giờ bạn hãy tạo một trang aspx mới với tên Captcha.aspx. Không cần quan tâm đến phần giao diện, bạn hãy copy đoạn mã trong phương thức CreateCaptcha() và đặt vào trong Page_Load, đồng thời sửa lại phần cuối của phương thức cho giống kết quả sau:
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 |
protected void Page_Load(object sender, EventArgs e) { string[] fonts = { "Arial Black", "Lucida Sans Unicode", "Comic Sans MS" }; const byte LENGTH = 5; // chuỗi để lấy các kí tự sẽ sử dụng cho captcha const string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; using (Bitmap bmp = new Bitmap(120, 30)) { using (Graphics g = Graphics.FromImage(bmp)) { // Tạo nền cho ảnh dạng sóng HatchBrush brush = new HatchBrush(HatchStyle.Wave, Color.White, Color.Wheat); g.FillRegion(brush, g.Clip); // Lưu chuỗi captcha trong quá trình tạo StringBuilder strCaptcha = new StringBuilder(); Random rand = new Random(); for (int i = 0; i < LENGTH; i++) { // Lấy kí tự ngẫu nhiên từ mảng chars string str = chars[rand.Next(chars.Length)].ToString(); strCaptcha.Append(str); // Tạo font với tên font ngẫu nhiên chọn từ mảng fonts Font font = new Font(fonts[rand.Next(fonts.Length)], 12, FontStyle.Strikeout | FontStyle.Italic); // Lấy kích thước của kí tự SizeF size = g.MeasureString(str, font); // Vẽ kí tự đó ra ảnh tại vị trí tăng dần theo i, vị trí top ngẫu nhiên g.DrawString(str, font, Brushes.Chocolate, i * size.Width + 3, rand.Next(2, 10)); font.Dispose(); } // Lưu captcha vào session Session["captcha"] = strCaptcha.ToString(); // Ghi ảnh trực tiếp ra luồng xuất theo định dạng gif Response.ContentType = "image/GIF"; bmp.Save(Response.OutputStream, ImageFormat.Gif); } } } |
Sau đó hãy sửa lại phần body của trang Default.aspx:
1 2 3 4 5 6 7 8 9 |
<form id="form1″" runat="server"> <div> <asp:Image ID="imgCaptcha" runat="server" ImageUrl="Captcha.aspx" /> <asp:ImageButton ID="imbReLoad" runat="server" ImageUrl="~/Images/ajax-arrows-green.gif" /><br /> <asp:TextBox runat="Server" ID="txtCaptcha" /> <br /> <asp:Button runat="Server" ID="btnSubmit" Text="Đồng ý" OnClick="btnSubmit_Click" /> <br /> <asp:Label ID="lblMessage" runat="server" ForeColor="Red"></asp:Label></div> </form> |
Có hai thay đổi nhỏ ở đoạn mã trên là thuộc tính ImageUrl của imgCaptcha được gán là trang Captcha.aspx, và sự kiện OnClick của imbReLoad cũng được bỏ đi. Mỗi khi imbReLoad được nhấn, nó sẽ PostBack lại trang và do đó imgCaptcha lại lấy về ảnh mới.
Cuối cùng phần code-behind của trang Default.aspx chỉ còn lại:
1 2 3 4 5 6 7 8 9 10 11 12 |
protected void Page_Load(object sender, EventArgs e) { } protected void btnSubmit_Click(object sender, EventArgs e) { if (txtCaptcha.Text.Equals(Session["captcha"].ToString(), StringComparison.OrdinalIgnoreCase)) lblMessage.Text = "Chuỗi xác nhận chính xác"; else lblMessage.Text = "Vui lòng nhập đúng chuỗi xác nhận"; } |
Chúc bạn thành công!