เมื่อเร็วๆ นี้ ฉันได้รับงานเพื่อพัฒนาฟังก์ชันรหัสยืนยันหน้า ฉันได้ศึกษาข้อมูลออนไลน์บางส่วน และเมื่อรวมกับความรู้ด้านการวาดภาพก่อนหน้านี้ ฉันจึงนำวิธีแก้ไขปัญหาต่อไปนี้ไปใช้ รหัสยืนยันที่สร้างขึ้นมีลักษณะดังนี้:
ปัญหาที่ต้องแก้ไข:
1. วิธีการสุ่มสร้างรูปภาพ
เพื่อสร้างออบเจ็กต์ System. Drawing.Bitmap และใช้ System. Drawing.Graphics เพื่อวาดลงในออบเจ็กต์บิตแมป
2. วิธีการส่งข้อมูลรูปภาพผ่านพารามิเตอร์ในวิธี WebService
เพื่อส่งออกวัตถุบิตแมปไปยังสตรีมไบต์ และ WebMothod ใช้อาร์เรย์ไบต์เพื่อส่งคืนสตรีมไบต์
ตัวอย่าง:
1. ใช้ VS.NET 2003 เพื่อสร้างโครงการ ASP.NET Webservice ชื่อบริการเริ่มต้นคือ MyService และ WebMethod ชื่อ GenerateVerifyImage จะถูกเพิ่มใน MyService รหัสของวิธีนี้มีดังนี้:
/// <summary>
/// สร้างรหัสยืนยันรูปภาพ
/// </สรุป>
/// <param name="nLen">ความยาวของรหัสยืนยัน</param>
/// <param name="strKey">พารามิเตอร์เอาต์พุต เนื้อหาของรหัสยืนยัน</param>
/// <returns>สตรีมไบต์ของภาพ</returns>
[วิธีการเว็บ]
ไบต์สาธารณะ [] GenerateVerifyImage (int nLen, อ้างอิงสตริง strKey)
-
int nBmpWidth = 13*nLen+5;
int nBmpHeight = 25;
System. Drawing.Bitmap bmp = new System. Drawing.Bitmap (nBmpWidth, nBmpHeight);
// 1. สร้างสีพื้นหลังแบบสุ่ม
int nRed,nGreen,nBlue; // สีที่ประกอบไปด้วยพื้นหลัง
System.Random rd = สุ่มใหม่ ((int) System.DateTime.Now.Ticks);
nRed = ถ.ถัดไป(255)%128+128;
nGreen = ถ.ถัดไป(255)%128+128;
nBlue = rd.Next(255)%128+128;
// 2. เติมพื้นหลังบิตแมป
กราฟ System. Drawing.Graphics = System. Drawing.Graphics.FromImage (bmp);
graph.FillRectangle (SolidBrush ใหม่ (System. Drawing.Color.FromArgb (nRed, nGreen, nBlue))
,0
,0
,nBmpWidth
,nBmpความสูง);
// 3. วาดเส้นรบกวนโดยใช้สีเข้มกว่าพื้นหลังเล็กน้อย
int nLines = 3;
ปากกา System. Drawing.Pen = ใหม่ System. Drawing.Pen (System. Drawing.Color.FromArgb (nRed-17, nGreen-17, nBlue-17), 2);
สำหรับ (int a =0;a< nLines;a++)
-
int x1 = rd.ถัดไป() % nBmpWidth;
int y1 = rd.ถัดไป() % nBmpHeight;
int x2 = rd.ถัดไป() % nBmpWidth;
int y2 = rd.ถัดไป() % nBmpHeight;
กราฟ DrawLine (ปากกา,x1,y1,x2,y2);
}
// ชุดอักขระที่ใช้สามารถขยายได้ตลอดเวลาและสามารถควบคุมความน่าจะเป็นที่อักขระจะปรากฏได้
string strCode = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 4. วนซ้ำเพื่อรับอักขระและวาด
สตริง strResult = "";
สำหรับ(int i=0;i<nLen;i++)
-
int x = (i*13 + ถ.ถัดไป(3));
int y = rd.Next(4) + 1;
// กำหนดแบบอักษร
System. Drawing.Font font = new System. Drawing.Font ("Courier New",
12 + ถ.ถัดไป()%4,
System. Drawing.FontStyle.Bold);
char c = strCode[rd.Next(strCode.Length)]; // รับอักขระแบบสุ่ม
strResult += c.ToString();
// วาดอักขระ
graph.DrawString(c.ToString(),
แบบอักษร,
ใหม่ SolidBrush(System. Drawing.Color.FromArgb(nRed-60+y*3,nGreen-60+y*3,nBlue-40+y*3))
เอ็กซ์,
ใช่);
}
// 5. สตรีมไบต์เอาต์พุต
System.IO.MemoryStream bstream = System.IO.MemoryStream(); ใหม่
bmp.Save(bstream,System. Drawing.Imaging.ImageFormat.Jpeg);
bmp.ทิ้ง();
graph.Dispose();
strKey = strResult;
ไบต์ [] byteReturn = bstream.ToArray();
bstream.Close();
กลับ byteReturn;
}
2. ทดสอบ WebMethod เพิ่ม WebForm อ้างอิง WebService ด้านบน และชื่ออ้างอิงคือ imagesvr เพิ่มโค้ดใน Page_Load:
...
imagevr.MyService imgsvr = รูปภาพใหม่ VR.MyService();
สตริง strKey = "";
ข้อมูลไบต์ [] = imgsvr.GenerateVerifyImage (5, อ้างอิง strKey);
Response.OutputStream.Write (ข้อมูล, 0, data.Length);
...
3. วิ่ง แต่ละครั้งที่มีการรีเฟรช WebForm รหัสยืนยันรูปภาพที่สร้างขึ้นใหม่จะปรากฏขึ้น และพารามิเตอร์เอาต์พุต strKey ของฟังก์ชันจะบันทึกเนื้อหาจริงของรหัสยืนยัน ซึ่งสามารถบันทึกไว้ในเซสชันเพื่อตรวจสอบได้
หลังจากพัฒนารหัสยืนยันรูปภาพครั้งที่แล้ว ตามคำแนะนำของเพื่อนบางคน โดยยึดหลักการที่ว่ารหัสยืนยันนั้นง่ายต่อการจดจำ (สำหรับคน) ถอดรหัสยาก และสวยงาม อัลกอริธึมการสร้างรหัสยืนยันได้รับการปรับปรุงให้ดีขึ้น และใช้วิธีการกรองรูปภาพเพื่อกรองรูปภาพ รหัสยืนยันอยู่ภายใต้การรบกวนป้องกันการแคร็ก และตัวอย่างรูปภาพที่ได้จะเป็นดังนี้:
เอฟเฟ็กต์ฟิลเตอร์ส่วนใหญ่ใช้อัลกอริธึมคลื่น ซึ่งสร้างเอฟเฟกต์การซ้อนโดยการประมวลผลรูปคลื่นไซน์ของแกน X และแกน Y คำอธิบายหลักของอัลกอริทึมมีดังนี้:
ส่วนตัว const double PI = 3.1415926535897932384626433832795;
ส่วนตัว const double PI2 = 6.283185307179586476925286766559;
/// <สรุป>
/// ภาพคลื่นไซน์บิดเบี้ยว
/// </สรุป>
/// <param name="srcBmp"></param>
/// <ชื่อพารามิเตอร์ = "bXDir"></ พารามิเตอร์>
/// <param name="nMultValue">ผลคูณแอมพลิจูดของรูปคลื่น</param>
/// <param name="dPhase">เฟสเริ่มต้นของรูปคลื่น ช่วงค่า [0-2*PI)</param>
/// <ส่งคืน></ส่งคืน>
ระบบสาธารณะ Drawing.Bitmap TwistImage (บิตแมป srcBmp, bool bXDir, double dMultValue, double dPhase)
-
System. Drawing.Bitmap destBmp = new Bitmap(srcBmp.Width,srcBmp.Height);
// เติมพื้นหลังบิตแมปด้วยสีขาว
กราฟ System. Drawing.Graphics = System. Drawing.Graphics.FromImage (destBmp);
graph.FillRectangle (SolidBrush ใหม่ (System. Drawing.Color.White), 0,0, destBmp.Width, destBmp.Height);
กราฟ.ทิ้ง();
double dBaseAxisLen = bXDir ? (สองเท่า)destBmp.Height : (สองเท่า)destBmp.Width;
for(int i=0;i<destBmp.Width;i++)
-
สำหรับ(int j=0;j<destBmp.Height;j++)
-
สองเท่า dx = 0;
dx = bXDir ? (PI2*(สองเท่า)j)/dBaseAxisLen : (PI2*(สองเท่า)i)/dBaseAxisLen;
dx += dเฟส;
double dy = Math.Sin(dx);
// รับสีของจุดปัจจุบัน
int nOldX = 0, nOldY = 0;
nOldX = bXDir ? i + (int)(dy*dMultValue) : i;
nOldY = bXDir ? j : j + (int)(dy*dMultValue);
System. Drawing.Color สี = srcBmp.GetPixel(i,j);
ถ้า(nOldX >= 0 && nOldX < destBmp.Width
&& nOldY >=0 && nOldY < destBmp.Height)
-
destBmp.SetPixel(nOldX,nOldY,สี);
-
-
}
ส่งคืน destBmp;
}
ภาพตัวอย่างที่จุดเริ่มต้นคือการซ้อนทับของเอฟเฟกต์รูปคลื่นสองแบบ เอฟเฟกต์ทั้งสองมีไว้สำหรับทิศทางของแกน X และทิศทางของแกน Y ตามลำดับ หากคุณยกเลิกการเติมสีพื้นหลังของขอบ คุณจะเห็นผลกระทบของ อัลกอริธึมบนกราฟิก ดังแสดงด้านล่าง:
รหัสยืนยันที่สร้างขึ้นในลักษณะนี้ดูเหมือนรหัสยืนยันบนเว็บไซต์ Google มาก แน่นอนว่าหากคุณสนใจ คุณสามารถเพิ่มเอฟเฟกต์ตัวกรองอื่นๆ ได้ เช่น การยืด การหมุน ภาพโมเสค เป็นต้น แต่โปรดทราบว่ายิ่งรหัสยืนยันเว็บไซต์ซับซ้อนมากเท่าไร คุณก็ยิ่งต้องหาจุดสมดุลระหว่างความเร็วและความปลอดภัยเท่านั้น