现在的位置: 首页 > 综合 > 正文

[转]大流量、高并发网站验证码解决方案

2012年06月14日 ⁄ 综合 ⁄ 共 5084字 ⁄ 字号 评论关闭

原文地址: 

http://www.oksvn.com/Article/Detail-71.shtml

 

摘录: 

大型站点都是把验证码服务器和应用服务器分开的。具体的做法有两种:

1.获取验证码的时候验证码服务器往客户端写验证cookies,提交的时候服务端获取这个cookie和提交上来的验证码,再去验证码服务器验证。

2.获取验证码的时候传个应用这边的session到验证码服务器那边,提交的时候服务端把应用这边的session和提交上来的验证码一起到验证码服务器验证。

  

实现例子:

首先要解决的一个问题就是怎么样把客户端请求的验证码数据存储起来而且要两边都能够访问我是这样解决的:

代码
using System;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace Flyimg.Verify.Server
{
    
public class CodeSession
    {
        
/// <summary>
        
/// 存放验证数据链表
        
/// </summary>
        private static LinkedList<CodeSession> VerifyCodeList = new LinkedList<CodeSession>();

        private string _SessionId;
        
private string _VerifyCode;

        /// <summary>
        
/// 构造函数
        
/// </summary>
        
/// <param name="strSessionId"></param>
        
/// <param name="strVerifyCode"></param>
        public CodeSession(string strSessionId, string strVerifyCode)
        {
            _SessionId 
= strSessionId;
            _VerifyCode 
= strVerifyCode;
        }

        /// <summary>
        
/// 添加验证码数据
        
/// </summary>
        
/// <param name="strSessionId"></param>
        
/// <param name="strVerifyCode"></param>
        
/// <returns></returns>
        public static string Add(string strSessionId, string strVerifyCode)
        {
            
bool bResult = false;

            LinkedListNode<CodeSession> CurrentPlay = new LinkedListNode<CodeSession>(new CodeSession(strSessionId, strVerifyCode));

            try
            {
                
//保持链表长度限制客户端连接数
                if (VerifyCodeList.Count < int.Parse(ConfigurationManager.AppSettings["Capacity"].ToString()))
                {
                    VerifyCodeList.AddFirst(CurrentPlay);
                }
                
else
                {
                    VerifyCodeList.RemoveLast();
                    VerifyCodeList.AddFirst(CurrentPlay);
                }
                bResult 
= true;
            }
            
catch
            {
                bResult 
= false;
            }

            return bResult.ToString();
        }

        /// <summary>
        
/// 删除验证码数据
        
/// </summary>
        
/// <param name="strSessionId"></param>
        
/// <param name="strVerifyCode"></param>
        public static void Remove(string strSessionId, string strVerifyCode)
        {
            CodeSession codesession 
= new CodeSession(strSessionId, strVerifyCode);
            VerifyCodeList.Remove(codesession);
        }

        /// <summary>
        
/// 验证验证码数据
        
/// </summary>
        
/// <param name="strSessionId"></param>
        
/// <param name="strVerifyCode"></param>
        
/// <returns></returns>
        public static string Verify(string strSessionId, string strVerifyCode)
        {
            
int iResult = 0;

            foreach (CodeSession codesession in VerifyCodeList)
            {
                
if (codesession._SessionId == strSessionId && codesession._VerifyCode == strVerifyCode)
                {
                    iResult 
= 1;
                    Remove(strSessionId, strVerifyCode);
                    
break;
                }
            }

            return iResult.ToString();
        }

        /// <summary>
        
/// 清除验证数据
        
/// </summary>
        public static void Clear()
        {
            VerifyCodeList.Clear();
        }
    }
}

 

有两个主要的方法,ADD(添加)和Verify(验证)还有个问题就是两边的应用能快速的访问这个区域。我采用的是socket

没有采用webservice的原因的这样既可以分布式的部署而且速度够快。在验证码web端配置文件中配置好验证码Server的IP地址就可以了。

在验证码web端获取到验证码数据后:

代码
try
{
    
//添加验证到验证服务器
    Common.AddToVerifyServer(Session.SessionID, this.strVerifyCode);
}
catch (Exception ex)
{
    Logger.Add(ex.Message);
}

//写cookie
General.SetCookie("VerifyKey", Session.SessionID, "flyimg.cn");

 

 

这样验证码web端的任务就完成了,验证码Server中就有数据显示了:

提交的时候:

 

代码
protected override void OnPostting(Object sender, DataEventArgs e)
{
    
if (string.IsNullOrEmpty(Request.Form["UserAccounts"]))
    {
    strError1 
= "请输入用户名!";
    }
    
else if (string.IsNullOrEmpty(Request.Form["UserPwd"]))
    {
    strError2 
= "请输入密  码!";
    }
    
else if (string.IsNullOrEmpty(Request.Form["VerifyCode"]))
    {
    strError3 
= "请输入验证玛!";
    }
    
else
    {
    
bool bResult = false;

    try 
        {            
        
//到验证服务器验证
        bResult = Common.Verify(ToolKit.Common.General.GetCookie("VerifyKey"), Request.Form["VerifyCode"]);
        }
        
catch (Exception ex)
        {
        Logger.Add(ex);
        }

    if (bResult)
    {
        
if (Request.Form["UserAccounts"== "admin" && Request.Form["UserPwd"== "123123")
        {
        General.SetCookie(
"user_id""admin");

        string strReturnUrl = Request.QueryString["url"];

        if (!string.IsNullOrEmpty(strReturnUrl))
        {
            Response.Redirect(HttpUtility.UrlDecode(Request.QueryString[
"url"]));
        }
        
else
        {
            Response.Redirect(
"/upload");
        }
        }
        
else
        {
        strError2 
= "用户名或者密码错误!";
        }
    }
    
else
    {
        strError3 
= "验证玛错误!";
    }
    }
}

 

好了。功能就是这样实现的。这是用第一种方式实现的,稍微修改下就可以改成第二种方式了。

下载地址:http://www.svnhost.cn/Download/Detail-108.shtml

Server端用到了一个开源的Socket类库Midapex.Net:

http://www.cnblogs.com/dyj057/archive/2008/04/18/1160392.html

谢谢,欢迎大家交流!enjoy... 

 

 

 

抱歉!评论已关闭.