再论安全验证码 - 实现数字、字母、中文混淆验证

    这几天博客都被垃圾评论困扰着,于是就有了一个写一个验证码的想法。这个验证码主要是增加机器识别的难度,当前网上各种流行的验证码中,感觉动网的验证码比较优秀,比较不容易被机器识别。

    从动网官网下载了动网.net 1.1版本,用Reflector反编译它的源代码。

    请先看动网验证码的截图:

 

系统自动生成中文、数字、字母的混合字符串,并且自动设置有效的验证码值。上图中的有效验证码值为“mejjh”,而图片全文为“mej的jh”,这样就可以有效地防止被机器识别出验证码了。

    我把动网里的验证码代码剥离出来,并作了一些修改。

    在动网源代码中,它生成的验证码参数设置是读取Request.QueryString值的,这里我们不再使用这种方式设置验证码,改用xml文件保存设置。

ContractedBlock.gif ExpandedBlockStart.gif XML配置
xml version="1.0" encoding="utf-8" ?>
<config>
  

  
<bgcolor value="LightBlue"/>
  

  
<bold value="true" />
  

  
<forecolor value="Blue" />
  

  
<fontfamily value="Arial, Helvetica, sans-serif,宋体" />
  

  
<fontsize value="20" />
  

  
<height value="70" />
  

  
<impurity value="2" />
  

  
<italic value="false" />
  

  
<width value="180" />
  

  
<number value="6" />
  

  
<codetext>
    
我人有的和主产不为这工要在地一上是中经以发了民同国木子123456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ]]>
  
codetext>
config>

 

再把xml文件的配置信息映射到一个类上:

ContractedBlock.gif ExpandedBlockStart.gif XML配置类
ExpandedBlockStart.gifContractedBlock.gif/**//// 
/// 验证码配置文件
/// 

public class ValidateCodeConfig
ExpandedBlockStart.gifContractedBlock.gif
{
ContractedSubBlock.gifExpandedSubBlockStart.gif    
属性#region 属性
    
private Color bgcolor;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 背景色
    
/// 

    public Color BgColor
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get return bgcolor; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
set { bgcolor = value; }
    }

    
private bool bold;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 是否粗体
    
/// 

    public bool Bold
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get return bold; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
set { bold = value; }
    }

    
private Color forecolor;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 颜色
    
/// 

    public Color ForeColor
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get return forecolor; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
set { forecolor = value; }
    }

    
private string fontFamily;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 字体
    
/// 

    public string FontFamily
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get return fontFamily; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
set { fontFamily = value; }
    }

    
private int fontSize;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 字体大小
    
/// 

    public int FontSize
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get return fontSize; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
set { fontSize = value; }
    }

    
private int height;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 高度
    
/// 

    public int Height
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get return height; }
        
set
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (300 < value)
                height 
= 300;
            
else
                height 
= value;
        }

    }

    
private int impurity;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 杂质
    
/// 

    public int Impurity
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get return impurity; }
        
set
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (30 < value)
                impurity 
= 30;
            
else
                impurity 
= value;
        }

    }

    
private bool italic;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 斜体
    
/// 

    public bool Italic
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get return italic; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
set { italic = value; }
    }

    
private int width;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 宽度
    
/// 

    public int Width
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get return width; }
        
set
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (300 < value)
                width 
= 300;
            
else
                width 
= value;
        }

    }

    
private char[] codetext;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 验证码字符
    
/// 

    public char[] CodeText
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get return codetext; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
set { codetext = value; }
    }

    
private int number;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 验证码字数
    
/// 

    public int Number
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
get return number; }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
set { number = value; }
    }

    
#endregion


ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 构造函数
    
/// 

    public ValidateCodeConfig()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        LoadXMLOnInit();
    }


ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// 
    
/// 加载config.xml配置
    
/// 

    private void LoadXMLOnInit()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        XmlDocument doc 
= new XmlDocument();
        doc.Load(HttpContext.Current.Server.MapPath(
"~/ValidateCode/config.xml"));
        
this.bgcolor = Color.FromName(doc.GetElementsByTagName("bgcolor").Item(0).Attributes["value"].Value);
        
this.bold = Boolean.Parse(doc.GetElementsByTagName("bold").Item(0).Attributes["value"].Value);
        
this.codetext = doc.GetElementsByTagName("codetext").Item(0).InnerText.ToCharArray();
        
this.fontFamily = doc.GetElementsByTagName("fontfamily").Item(0).Attributes["value"].Value;
        
this.fontSize = int.Parse(doc.GetElementsByTagName("fontsize").Item(0).Attributes["value"].Value);
        
this.forecolor = Color.FromName(doc.GetElementsByTagName("forecolor").Item(0).Attributes["value"].Value);
        
this.height = int.Parse(doc.GetElementsByTagName("height").Item(0).Attributes["value"].Value);
        
this.impurity = int.Parse(doc.GetElementsByTagName("impurity").Item(0).Attributes["value"].Value);
        
this.italic = Boolean.Parse(doc.GetElementsByTagName("italic").Item(0).Attributes["value"].Value);
        
this.width = int.Parse(doc.GetElementsByTagName("width").Item(0).Attributes["value"].Value);
        
this.number = int.Parse(doc.GetElementsByTagName("number").Item(0).Attributes["value"].Value);
    }

}

 

在绘图方法中调用这个类,并为其设置缓存依赖:

ContractedBlock.gif ExpandedBlockStart.gif 为配置文件设置缓存依赖
ExpandedBlockStart.gifContractedBlock.gif/**//// 
/// 为配置文件设置缓存依赖
/// 

private void LoadConfig()
ExpandedBlockStart.gifContractedBlock.gif
{
    
if (HttpRuntime.Cache["ValidateCodeConfig"== null)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        config 
= new ValidateCodeConfig();
        CacheDependency dep 
= new CacheDependency(HttpContext.Current.Server.MapPath("~/ValidateCode/config.xml"));
        HttpRuntime.Cache.Insert(
"ValidateCodeConfig", config, dep, DateTime.MaxValue,
            TimeSpan.Zero);
    }

    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        config 
= (ValidateCodeConfig)HttpRuntime.Cache["ValidateCodeConfig"];
    }

}

 

之后,我们就可以开始写生成验证码的主要方法了:

ContractedBlock.gif ExpandedBlockStart.gif 验证码主要方法
ExpandedBlockStart.gifContractedBlock.gif/**//// 
/// 验证码字体样式
/// 

/// 

private FontStyle GetFontStyle()
ExpandedBlockStart.gifContractedBlock.gif
{
    
if (config.Bold && config.Italic)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
return (FontStyle.Italic | FontStyle.Bold);
    }

    
if (config.Bold)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
return FontStyle.Bold;
    }

    
if (config.Italic)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
return FontStyle.Italic;
    }

    
return FontStyle.Regular;
}


private Bitmap GetneralCodeImage()
ExpandedBlockStart.gifContractedBlock.gif
{
    
bool flag3;
    Random random 
= new Random();
    Bitmap image 
= new Bitmap(config.Width, config.Height);
    Graphics graphics 
= Graphics.FromImage(image);
    graphics.Clear(config.BgColor);
    
int length = Directory.GetFiles(Server.MapPath("~/ValidateCode/"), "*.gif").Length;
    
int backgroundfile = random.Next(1, length);

    Brush brush 
= new TextureBrush(new Bitmap(Server.MapPath("~/ValidateCode/" + backgroundfile.ToString() + ".gif")));
    Rectangle rect 
= new Rectangle(00, config.Width, config.Height);
    graphics.FillRectangle(brush, rect);
    
string[] strColorArray = new string[]
ExpandedSubBlockStart.gifContractedSubBlock.gif

"#666666""#003300""#009900""#330000""#333300"
"#336600""#660000""#663300""#666600""#FF99FF",
"#FF33FF""#CCCCFF""#CC66FF""#CC00FF""#9999FF",
"#9933FF""#9900FF""#FF00FF""#996633""#CC3333",
"#FF3333""#6633FF""#0033FF""#336666""#CC9900",
"#6633CC""#66FF66""#009999""#99CC00""#615379",
"#E6649E""#B5B495""#73CEA7"
}
;
    
bool istop = random.Next(02== 0;
    Pen pen 
= new Pen(ColorTranslator.FromHtml(strColorArray[random.Next(0, strColorArray.Length)]), 2f);
    pen.DashStyle 
= DashStyle.Solid;
    Point[] randomPointGroup 
= this.GetRandomPointGroup(istop);
    
for (int i = 0; i < randomPointGroup.Length; i += 2)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        graphics.DrawLine(pen, randomPointGroup[i], randomPointGroup[i 
+ 1]);
    }

    
string input = "";
    
for (int j = 0; j < config.Number; j++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        input 
+= config.CodeText[random.Next(config.CodeText.Length)].ToString();
    }

    
string[] strArray2 = new string[config.Number + 1];
    
int index = 0;
Label_0313:
    
while (index != config.Number)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
string str2 = strColorArray[random.Next(0, strColorArray.Length)];
        strArray2[index] 
= str2;
        index
++;
        
for (int n = 0; n < strArray2.Length; n++)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (strArray2[n] == str2)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
goto Label_0313;
            }

            
if (n == (strArray2.Length - 1))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                strArray2[index] 
= str2;
                index
++;
            }

        }

    }

    
char[] chArray2 = input.ToCharArray();
    
int num8 = random.Next(0, config.Number - 1);
    
string str3 = strArray2[num8];
    
int num9 = random.Next(0, config.Number - 2+ 1;
    num9 
= (num9 == 1? 2 : num9;
    
int[] numArray = new int[num9];
    numArray[
0= num8;
    
for (int k = 1; k < num9; k++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
int num11 = random.Next(0, config.Number - 1);
        
bool flag2 = false;
        
for (int num12 = 0; num12 < k; num12++)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (numArray[num12] == num11)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                flag2 
= true;
                
break;
            }

        }

        
if (!flag2)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            numArray[k] 
= num11;
        }

        
else
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            k
--;
        }

    }

    
do
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
string str4 = strColorArray[random.Next(0, strColorArray.Length)];
        flag3 
= false;
        
for (int num13 = 0; num13 < strArray2.Length; num13++)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (str4 == strArray2[num13])
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                flag3 
= true;
                
break;
            }

        }

    }

    
while (flag3);
    
string strRegexString = "";
    
string strRegexValidateType = "";

    
int intValidateType = random.Next(03);

    
bool flag4 = false;
    
while (!flag4)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        Match matchChinese;
        Match matchLetter;
        Match matchNumber;
        
switch (intValidateType)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
case 0:
                
if (!Regex.IsMatch(input, @"[\u4e00-\u9fa5]+"))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
goto Label_RandomCodeType;
                }

                flag4 
= true;
                strRegexValidateType 
= "中文字体";
                matchChinese 
= Regex.Match(input, @"[\u4e00-\u9fa5]+", RegexOptions.Multiline | RegexOptions.IgnoreCase);
                
goto Label_ChineseRegexResult;

            
case 1:
                
if (!Regex.IsMatch(input, "[a-zA-Z]+"))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
goto Label_RandomCodeType;
                }

                flag4 
= true;
                strRegexValidateType 
= "英文字母";
                matchLetter 
= Regex.Match(input, "[a-zA-Z]+", RegexOptions.Multiline | RegexOptions.IgnoreCase);
                
goto Label_LetterRegexResult;

            
case 2:
                
if (!Regex.IsMatch(input, "[0-9]+"))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
goto Label_RandomCodeType;
                }

                flag4 
= true;
                strRegexValidateType 
= "数字";
                matchNumber 
= Regex.Match(input, "[0-9]+", RegexOptions.Multiline | RegexOptions.IgnoreCase);
                
goto Label_NumberRegexResult;

            
case 3:
                
if (Regex.IsMatch(input, @"[^\u4e00-\u9fa5|a-zA-Z|0-9]"))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    flag4 
= true;
                    strRegexValidateType 
= "特殊字符";
                    strRegexString 
= new Regex(@"[\u4e00-\u9fa5|a-zA-Z|0-9]+").Replace(input, "");
                }

                
goto Label_RandomCodeType;

            
default:
                
goto Label_RandomCodeType;
        }

    Label_ChineseRegexSuccess:
        strRegexString 
= strRegexString + matchChinese.Value;
        matchChinese 
= matchChinese.NextMatch();
    Label_ChineseRegexResult:
        
if (matchChinese.Success)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
goto Label_ChineseRegexSuccess;
        }

        
goto Label_RandomCodeType;
    Label_LetterRegexSuccess:
        strRegexString 
= strRegexString + matchLetter.Value;
        matchLetter 
= matchLetter.NextMatch();
    Label_LetterRegexResult:
        
if (matchLetter.Success)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
goto Label_LetterRegexSuccess;
        }

        
goto Label_RandomCodeType;
    Label_NumberRegexSuccess:
        strRegexString 
= strRegexString + matchNumber.Value;
        matchNumber 
= matchNumber.NextMatch();
    Label_NumberRegexResult:
        
if (matchNumber.Success)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
goto Label_NumberRegexSuccess;
        }


    Label_RandomCodeType:
        
if (!flag4)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            intValidateType 
= random.Next(03);
        }

    }

    
int num16 = 0;
    
for (int m = 0; m < chArray2.Length; m++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
int num21;
        
int num18 = config.FontSize;
        
int num19 = (m == 0? 10 : 25;
        num16 
+= num19;
        
int num20 = num16;
        
if (istop)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            num21 
= random.Next(15, config.Height - 35);
        }

        
else
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            num21 
= random.Next(0, config.Height - 45);
        }

        
bool flag5 = false;
        
if ((((('.' != chArray2[m]) && ('_' != chArray2[m])) && (('*' != chArray2[m]) && ('`' != chArray2[m]))) && ((('~' != chArray2[m]) && ('.' != chArray2[m])) && ((',' != chArray2[m]) && ('\'' != chArray2[m])))) && ((('-' != chArray2[m]) && ('|' != chArray2[m])) && ('\\' != chArray2[m])))
ExpandedSubBlockStart.gifContractedSubBlock.gif
        {
            
char ch1 = chArray2[m];
        }

        graphics.DrawString(chArray2[m].ToString(), 
new Font(config.FontFamily, flag5 ? ((float)(num18 + 30)) : ((float)num18), flag5 ? FontStyle.Bold : this.GetFontStyle()), new SolidBrush(ColorTranslator.FromHtml(strArray2[m])), (float)num20, (float)num21);
    }


    graphics.DrawString(
"输入图中出现的"new Font("Verdana", 10f, FontStyle.Regular), new SolidBrush(ColorTranslator.FromHtml("#008000")), (2 == intValidateType) ? ((float)18) : ((float)4), istop ? ((float)2) : ((float)(config.Height - 16)));
    graphics.DrawString(strRegexValidateType, 
new Font("Verdana", 10f, FontStyle.Bold), new SolidBrush(ColorTranslator.FromHtml("#FF0000")), (2 == intValidateType) ? ((float)126) : ((float)110), istop ? ((float)2) : ((float)(config.Height - 16)));

    graphics.Dispose();
    Response.Cookies.Add(
new HttpCookie("ValidateCode", strRegexString.ToLower()));
    
return image;
}


ExpandedBlockStart.gifContractedBlock.gif
/**//// 
/// 杂质
/// 

/// 
/// 

private Point[] GetRandomPointGroup(bool istop)
ExpandedBlockStart.gifContractedBlock.gif
{
    Point[] pointArray 
= new Point[config.Impurity * 2];
    
for (int i = 0; i < pointArray.Length; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
int num2 = new Random().Next(1000000099999999);
        
int x = new Random((num2 / (i + 2)) * (i + 1)).Next(0, config.Width);
        
int y = new Random((num2 / (x + 2)) * (x + 1)).Next(istop ? 16 : 0, istop ? config.Height : (config.Height - 16));
        pointArray[i] 
= new Point(x, y);
    }

    
return pointArray;
}

 

最后,在Page_Load中调用上面的方法:

private   void  Page_Load( object  sender, EventArgs e)
ExpandedBlockStart.gifContractedBlock.gif
{
    
this.LoadConfig();
    
base.Response.ContentType = "image/gif";
    
this.GetneralCodeImage().Save(base.Response.OutputStream, ImageFormat.Gif);
}

 

演示效果如图:

 

再论安全验证码 - 实现数字、字母、中文混淆验证_第1张图片

 

DEMO源码下载:http://www.box.net/shared/g324d08ivy

转载于:https://www.cnblogs.com/moozi/archive/2008/11/28/1343383.html

你可能感兴趣的:(再论安全验证码 - 实现数字、字母、中文混淆验证)