架構概覽
PicHandler.ashx (IHttpHandler + IRequiresSessionState):HTTP 端點,產生圖片並寫入 Session。
VryImgGen:核心繪圖類別,封裝字體、顏色、雜訊、波形扭曲、中英文字元產生。
HttpHandler 實作
public class PicHandler : IHttpHandler, IRequiresSessionState
{
private readonly VryImgGen _gen = new VryImgGen();
public void ProcessRequest(HttpContext context)
{
string code = GenerateCode(6);
context.Session["CheckCode"] = code; // 驗證碼存 Session
_gen.Chaos = true;
_gen.ChaosWight = 40;
_gen.FontSize = 25;
_gen.Padding = 3;
using (var bmp = _gen.CreateImage(code))
using (var ms = new MemoryStream())
{
bmp.Save(ms, ImageFormat.Jpeg);
context.Response.ClearContent();
context.Response.ContentType = "image/jpeg";
context.Response.BinaryWrite(ms.ToArray());
}
context.Response.End();
}
private string GenerateCode(int len)
{
// 簡易示範:實際建議使用 VryImgGen.CreateVerifyCode
var rnd = new Random();
const string chars = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
return new string(Enumerable.Range(0, len).Select(_ => chars[rnd.Next(chars.Length)]).ToArray());
}
public bool IsReusable => false;
}
核心繪圖類別 VryImgGen 關鍵功能
public class VryImgGen
{
public int Length { get; set; } = 5;
public int FontSize { get; set; } = 20;
public int Padding { get; set; } = 4;
public bool Chaos { get; set; } = true;
public Color ChaosColor { get; set; } = Color.LightGray;
public int ChaosWight { get; set; } = 1;
public Color BackgroundColor { get; set; } = Color.White;
public Color[] Colors { get; set; } = { Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple };
public string[] Fonts { get; set; } = { "Arial", "Georgia" };
// 正弦波扭曲演算法(大幅提升 OCR 辨識難度)
public Bitmap TwistImage(Bitmap src, bool xDir, double mult, double phase) { /* ... */ }
public Bitmap CreateImage(string code)
{
// 1. 計算畫布大小
// 2. 畫雜訊點
// 3. 逐字繪製:隨機字體、顏色、Y 軸偏移
// 4. 畫邊框
// 5. 套用 TwistImage 扭曲
return bmp;
}
// 產生驗證碼字串:支援純英數、或混合中文(GB2312 編碼區)
public string CreateVerifyCode(int codeLen, int zhCharsCount) { /* ... */ }
protected char CreateEnOrNumChar() { /* ... */ }
protected char CreateZhChar() { /* GB2312 區位碼隨機組合 */ }
}
前端調用
<img id="captcha" src="PicHandler.ashx" alt="驗證碼" style="vertical-align:middle; cursor:pointer;" />
<a href="javascript:void(0);" onclick="document.getElementById('captcha').src='PicHandler.ashx?'+Math.random();">換一張</a>
<input type="text" id="txtCode" maxlength="6" />
後端驗證
if (String.Equals(txtCode.Text.Trim(), Session["CheckCode"]?.ToString(), StringComparison.OrdinalIgnoreCase))
{
// 通過
}
部署注意事項
- 專案必須引用
System.Drawing.Common (NuGet),否則 Linux Docker 容器需安裝 libgdiplus。
- Session 模式若為 InProc,Web Farm 需改用 StateServer/Redis 共享驗證碼。
- 字體檔案:伺服器需安裝指定字體(Arial, Georgia 等),否則會 fallback 導致樣式不一致。
現代化建議
- 改用 SkiaSharp 跨平台繪圖,免 GDI+ 依賴,效能更佳。
- 前端整合 Google reCAPTCHA v3 / hCaptcha / Turnstile,以行為分析取代圖形辨識,兼顧安全與 UX。