驗證碼是防止機器人惡意提交的基本防線。本文示範 MVC 控制器產生驗證碼圖片、Session 儲存驗證碼、前端顯示與更換、以及驗證邏輯。
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Web;
namespace Utility
{
public class ValidateCode
{
/// <summary>產生隨機碼</summary>
public static string CreateRandomCode(int length)
{
const string chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; // 排除易混淆字元
var random = new Random();
var code = new char[length];
for (int i = 0; i < length; i++)
code[i] = chars[random.Next(chars.Length)];
return new string(code);
}
/// <summary>建立驗證碼圖片並直接輸出至 Response</summary>
public static void CreateImage(string code)
{
int width = code.Length * 22;
using (var bitmap = new Bitmap(width, 30))
using (var g = Graphics.FromImage(bitmap))
{
g.Clear(Color.AliceBlue);
g.DrawRectangle(Pens.Black, 0, 0, width - 1, 29);
// 背景雜訊
var rand = new Random();
for (int i = 0; i < 30; i++)
{
g.DrawRectangle(Pens.LightGray, rand.Next(width), rand.Next(30), 1, 1);
}
// 字體與顏色陣列
string[] fonts = { "Arial", "Verdana", "Tahoma" };
Color[] colors = { Color.Black, Color.DarkBlue, Color.DarkGreen, Color.Maroon };
// 逐字繪製,隨機旋轉、字體、顏色
for (int i = 0; i < code.Length; i++)
{
var font = new Font(fonts[rand.Next(fonts.Length)], 16, FontStyle.Bold);
var brush = new SolidBrush(colors[rand.Next(colors.Length)]);
float angle = rand.Next(-30, 30);
g.TranslateTransform(16 + i * 20, 15);
g.RotateTransform(angle);
g.DrawString(code[i].ToString(), font, brush, 0, 0, StringFormat.GenericTypographic);
g.RotateTransform(-angle);
g.TranslateTransform(-(16 + i * 20), -15);
}
// 輸出 GIF
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ContentType = "image/gif";
using (var ms = new MemoryStream())
{
bitmap.Save(ms, ImageFormat.Gif);
HttpContext.Current.Response.BinaryWrite(ms.ToArray());
}
}
}
}
}
public class CommonController : Controller
{
[OutputCache(Duration = 0, NoStore = true)] // 禁止快取
public ActionResult VCode()
{
string code = ValidateCode.CreateRandomCode(4);
Session["VCode"] = code; // 儲存至 Session
ValidateCode.CreateImage(code); // 直接輸出圖片
return new EmptyResult(); // 已在 CreateImage 中寫入 Response
}
public JsonResult ValidateCode(string inputCode)
{
string sessionCode = Session["VCode"] as string;
bool valid = !string.IsNullOrEmpty(sessionCode)
&& string.Equals(sessionCode, inputCode, StringComparison.OrdinalIgnoreCase);
return Json(new { success = valid }, JsonRequestBehavior.AllowGet);
}
}
<img id="vcodeImg" src="/Common/VCode" width="80" height="30" style="vertical-align:middle; cursor:pointer;" title="點擊更換" />
<a href="javascript:;" id="refreshVCode">換一張</a>
<input type="text" id="txtVCode" name="vcode" maxlength="4" />
<script>
// 點擊圖片或連結更換
$("#vcodeImg, #refreshVCode").click(function () {
$("#vcodeImg").attr("src", "/Common/VCode?" + new Date().getTime()); // 加時間戳防快取
});
// 表單提交前驗證 (AJAX 範例)
$("#btnSubmit").click(function () {
var code = $("#txtVCode").val();
$.getJSON("/Common/ValidateCode", { inputCode: code }, function (resp) {
if (resp.success) {
// 通過,提交表單
$("form").submit();
} else {
alert("驗證碼錯誤");
$("#vcodeImg").click(); // 自動換碼
}
});
});
</script>
[OutputCache(Duration=0, NoStore=true)] + 前端加時間戳查詢字串。