ASP.net 验证码(C#)(转)

ASP.Net的验证码实现

一般传统的验证码图像一般采用一些CGIISAPI程序加上一些加密代码来动态生成图像,ASP大多采用COM组件实现,相当辛苦。

ASP.Net中欲实现动态验证码却相当容易,笔者大致的思路:

1、  了安全起见,一般存在于CGI程序的url中的验证码加密串最好不要出现在html表单中,而是采用session变量存储,这样验证码的校验会很容易。

2、  采用一个单独的aspx页面专门产生动态程序,要显示的图形验证码信息存在于session中,而一个系统中有可能存在多个表单,为满足整个系统要求可以在aspx后加一个确定的session key的名称,例如

<img src=”http://xxxx/Genimg/viewImg.aspx?sessionKeyName=abc”> 此处的abc就是登录页在第一次输出表单给客户端自动生成一个随机字符串存储在session中的key名称,在服务器端脚本中可以通过session(“abc”)获得生成的字符串(验证码)到底是多少,通过和用户在表单的验证码输入框中输入的内容比较来确定用户是否通过正常的ie浏览器来访问表单。

3、  在表单的第一次显示(get方法)时,生成一个随机数字符串,存入session(“abc”)中,同时将abc作为sessionKeyName的值加入到验证码图形显示生成程序viewImg.aspxurl串中。

4、  ViewImg.aspx分析sessionKeyName,获取session(“abc”)的具体值,利用GDI+产生内存图像,然后修改http header,按照content-type=images/png的格式输出二进制流,这样客户的浏览器会显示出一幅图像,图像表达的内容就是验证码。

5、  当用户填入验证码后,提交到表单验证程序,首先考察其中的验证码输入字段,发现不匹配session(“abc”)马上拒绝,甚至可以累计失败登录次数,乃至拒绝此IP连接,保护系统;匹配session中的存储值,可以进行进一步的其他处理(譬如登录处理,文章发表等),当然也注意销毁此session变量(如果以后不需要)。

6、  不同的表单,可以分配不同的session变量名,这样一个ViewImg.aspx可以为系统多个表单服务。


示例代码如下:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Drawing;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class test : System.Web.UI.Page
{
    private void Page_Load(object sender, System.EventArgs e)
    {
        this.CreateCheckCodeImage(GenerateCheckCode());
    }

    #region web 窗体设计器生成的代码
    override protected void OnInit(EventArgs e)
    {
        //
        // CODEGEN: 该调用是 asp.NET web 窗体设计器所必需的。
        //
        InitializeComponent();
        base.OnInit(e);
    }

    /// <summary>
    /// 设计器支持所需的方法 - 不要使用代码编辑器修改
    /// 此方法的内容。
    /// </summary>
    private void InitializeComponent()
    {
        this.Load += new System.EventHandler(this.Page_Load);
    }
    #endregion

    private string GenerateCheckCode()
    {
        int number;
        char code;
        string checkCode = String.Empty;

        System.Random random = new Random();

        for (int i = 0; i < 5; i++)
        {
            number = random.Next();

            if (number % 2 == 0)
                code = (char)('0' + (char)(number % 10));
            else
                code = (char)('A' + (char)(number % 26));

            checkCode += code.ToString();
        }
        //Response.Cookies.Add(new HttpCookie("CheckCode", checkCode)); 

        string SessionKeyName = Request.QueryString["SessionKeyName"];
        Session[SessionKeyName] = checkCode;//用于客户端校验码比较

        return checkCode;
    }

    private void CreateCheckCodeImage(string checkCode)
    {
        if (checkCode == null || checkCode.Trim() == String.Empty)
            return;

        System.Drawing.Bitmap image = new System.Drawing.Bitmap((int)Math.Ceiling((checkCode.Length * 12.5)), 22);
        Graphics g = Graphics.FromImage(image);

        try
        {
            //生成随机生成器
            Random random = new Random();

            //清空图片背景色
            g.Clear(Color.White);

            //画图片的背景噪音线
            for (int i = 0; i < 25; i++)
            {
                int x1 = random.Next(image.Width);
                int x2 = random.Next(image.Width);
                int y1 = random.Next(image.Height);
                int y2 = random.Next(image.Height);

                g.DrawLine(new Pen(Color.Silver), x1, y1, x2, y2);
            }

            Font font = new System.Drawing.Font("Arial", 12, (System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic));
            System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.Blue, Color.DarkRed, 1.2f, true);
            g.DrawString(checkCode, font, brush, 2, 2);

            //画图片的前景噪音点
            for (int i = 0; i < 100; i++)
            {
                int x = random.Next(image.Width);
                int y = random.Next(image.Height);

                image.SetPixel(x, y, Color.FromArgb(random.Next()));
            }

            //画图片的边框线
            g.DrawRectangle(new Pen(Color.Silver), 0, 0, image.Width - 1, image.Height - 1);

            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
            Response.ClearContent();
            Response.ContentType = "image/Gif";
            Response.BinaryWrite(ms.ToArray());
        }
        finally
        {
            g.Dispose();
            image.Dispose();
        }
    }
}
==============================================
新建测试页Test1.aspx和Test2.aspx

Test1.aspx,代码如下:
<body>
    <form id="form1" runat="server">
    <div>
    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" /><br />
        &nbsp;
        <asp:Image ID="Image1" runat="server" ImageUrl="~/ValidateCode.aspx?SessionKeyName=CheckCode1" />//该图片将用于显示验证码
    </div>
    </form>
</body>

Test1.aspx.cs的代码如下:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Test : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    protected void Button1_Click(object sender, EventArgs e)
    {

        if (this.TextBox1.Text.ToString().Trim() == Session["CheckCode1"].ToString())
        {
            Response.Write("<script lauguage='javascript'>alert('验证成功');</script>");
        }
    }

}
=====
Test2.aspx,代码如下:
<body>
    <form id="form2" runat="server">
    <div>
    <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
        <asp:Button ID="Button2" runat="server" Text="Button" OnClick="Button2_Click" /><br />
        &nbsp;
        <asp:Image ID="Image2" runat="server" ImageUrl="~/ValidateCode.aspx?SessionKeyName=CheckCode2" />//该图片将用于显示验证码
    </div>
    </form>
</body>

Test2.aspx.cs的代码如下:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Test : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    protected void Button2_Click(object sender, EventArgs e)
    {

        if (this.TextBox2.Text.ToString().Trim() == Session["CheckCode2"].ToString())
        {
            Response.Write("<script lauguage='javascript'>alert('验证成功');</script>");
        }
    }

}
==============
这样就可以实现两个不同表单分别验证了。

这里有一个问题是:如果把Test2.aspx页面的表单一起放到Test1.aspx页面,那么第一次打开Test1.aspx时,验证前一个表单,会出错,经调试,发现Session["CheckCode1"]的值为null,但图片正常显示,同时Session["CheckCode2"]的值正常。不过,刷新页面以后就好了,不知道怎么回事,希望能得到大家的意见。

posted @ 2006-09-07 15:49  Kevin Lin  阅读(904)  评论(0编辑  收藏  举报