Недавно я получил на работе задание разработать функцию кода проверки страницы. Я ознакомился с некоторой онлайн-информацией и в сочетании со своими предыдущими знаниями в области рисования реализовал следующее решение. Сгенерированный код проверки выглядит следующим образом:
Проблемы, которые необходимо решить:
1. Как случайным образом генерировать изображения
для создания объектов System.Drawing.Bitmap и использовать System.Drawing.Graphics для рисования в растровых объектах.
2. Как передать данные изображения через параметры в методе WebService
для вывода объекта Bitmap в поток байтов, а WebMothod использует массив байтов для возврата потока байтов.
Пример:
1. Используйте VS.NET 2003 для создания проекта веб-службы ASP.NET. Имя службы по умолчанию — MyService, а к MyService добавляется веб-метод с именем GenerateVerifyImage. Код этого метода следующий:
/// <summary>
/// Генерируем код проверки изображения
/// </сводка>
/// <param name="nLen">Длина проверочного кода</param>
/// <param name="strKey">Выходные параметры, содержимое кода проверки</param>
/// <returns>Поток байтов изображения</returns>
[Веб-метод]
public byte[] GenerateVerifyImage(int nLen,ref string strKey)
{
int nBmpWidth = 13*nLen+5;
интервал nBmpHeight = 25;
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(nBmpWidth,nBmpHeight);
// 1. Генерация случайного цвета фона;
int nRed,nGreen,nBlue // Тройной цвет фона;
System.Random rd = new Random((int)System.DateTime.Now.Ticks);
nRed = rd.Next(255)%128+128;
nGreen = rd.Next(255)%128+128;
nBlue = rd.Next(255)%128+128
// 2. Заполняем растровый фон
График System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmp);
graph.FillRectangle(new SolidBrush(System.Drawing.Color.FromArgb(nRed,nGreen,nBlue))
,0
,0
,nBmpWidth
,nBmpHeight);
// 3. Нарисуйте интерференционные линии, используя цвет немного темнее фона.
интервал nLines = 3;
System.Drawing.Pen pen = новый System.Drawing.Pen(System.Drawing.Color.FromArgb(nRed-17,nGreen-17,nBlue-17),2);
for(int a =0;a< nLines;a++)
{
int x1 = rd.Next() % nBmpWidth;
int y1 = rd.Next() % nBmpHeight;
int x2 = rd.Next() % nBmpWidth;
int y2 = rd.Next() % nBmpHeight;
Graph.DrawLine(pen,x1,y1,x2,y2);
}
// Используемый набор символов можно расширить в любой момент и контролировать вероятность появления символов
string strCode = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
// 4. Цикл для получения символов и их рисования;
строка strResult = "";
for(int i=0;i<nLen;i++)
{
int x = (i*13 + rd.Next(3));
int y = rd.Next(4) + 1
// Определяем шрифт
System.Drawing.Font font = новый System.Drawing.Font("Курьер Новый",
12 + рд.Следующий()%4,
System.Drawing.FontStyle.Bold);
char c = strCode[rd.Next(strCode.Length)] // Получаем случайные символы
strResult += c.ToString();
// Рисуем символы
график.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.Dispose();
график.Dispose();
стрКей = стрРезультат;
byte[] byteReturn = bstream.ToArray();
bstream.Close();
вернуть byteReturn;
}
2. Протестируйте WebMethod, добавьте WebForm, укажите указанный выше WebService и имя ссылки — imagesvr. Добавьте код в Page_Load:
...
imagesvr.MyService imgsvr = новые imagesvr.MyService();
строка strKey = "";
byte[] данные = imgsvr.GenerateVerifyImage(5,ref strKey);
Response.OutputStream.Write(данные,0,данные.Длина);
...
3. Бежать. Каждый раз, когда веб-форма обновляется, будет отображаться новый сгенерированный код проверки изображения, а выходной параметр strKey функции сохраняет фактическое содержимое кода проверки, который можно сохранить в сеансе для проверки.
После разработки кода проверки изображения в прошлый раз, на основе предложений некоторых друзей, на основе принципа, что код проверки легко распознается (для людей), его трудно взломать и он красив, алгоритм генерации кода проверки был улучшен, и для фильтрации изображений использовался метод фильтра изображений. Код проверки подвергается воздействию помех, препятствующих взлому, и пример результирующего изображения выглядит следующим образом:
Эффект фильтра в основном использует волновой алгоритм, который создает эффект суперпозиции путем обработки синусоидального сигнала по осям X и Y. Основное описание алгоритма следующее:
Private const double PI = 3.1415926535897932384626433832795;
частный const double PI2 = 6.283185307179586476925286766559
/// <сводка>
/// Синусоидальная волна искажает изображение
/// </сводка>
/// <param name="srcBmp"></param>
/// <param name="bXDir"></param>
/// <param name="nMultValue">Амплитуда кратная формы сигнала</param>
/// <param name="dPhase">Начальная фаза сигнала, диапазон значений [0-2*PI)</param>
/// <возвращается></возвращается>
public System.Drawing.Bitmap TwistImage(Bitmap 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(new SolidBrush(System.Drawing.Color.White),0,0,destBmp.Width,destBmp.Height);
график.Dispose();
двойной dBaseAxisLen = bXDir ? (double)destBmp.Height: (double)destBmp.Width
for(int i=0;i<destBmp.Width;i++)
{
for(int j=0;j<destBmp.Height;j++)
{
двойной dx = 0;
dx = bXDir ? (PI2*(double)j)/dBaseAxisLen: (PI2*(double)i)/dBaseAxisLen;
dx += dPhase;
double dy = Math.Sin(dx);
// Получаем цвет текущей точки
int nOldX = 0, nOldY = 0;
nOldX = bXDir я + (int) (dy*dMultValue): я;
nOldY = bXDir ? j : j + (int)(dy*dMultValue);
System.Drawing.Color color = srcBmp.GetPixel(i,j);
if(nOldX >= 0 && nOldX < destBmp.Width
&& nOldY >=0 && nOldY < destBmp.Height)
{
destBmp.SetPixel(nOldX,nOldY,color);
}
}
}
Вернуть destBmp;
}
Пример изображения в начале представляет собой суперпозицию двух эффектов формы волны. Эти два эффекта предназначены для направления оси X и направления оси Y соответственно. Если вы отмените заливку цвета фона края, вы можете увидеть влияние. алгоритм на графике, как показано ниже:
Сгенерированный таким образом код подтверждения очень похож на код подтверждения на сайте Google. Конечно, если вам интересно, вы также можете добавить другие эффекты фильтра, такие как растяжение, вращение, мозаику и т. д. Но учтите, что чем сложнее код проверки сайта, тем лучше вам необходимо найти баланс между скоростью и безопасностью.