slimboy

从dotnet青年到php新人,关注互联网开发
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

asp.net 真正实现完全跨域单点登录

Posted on 2009-12-29 15:25  slimboy  阅读(7945)  评论(7编辑  收藏  举报

asp.net 跨域单点登录    

关键字:单点登录   跨域    跨域单点登录

源代码下载:http://download.csdn.net/source/1571879 

单点登录Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

asp.net跨域单点登录分为:

1、跨子域单点登录。如 blog.a.com 和 info.a.com 这2个站点同属一个主域.a.com,实现跨子域单点登录很简单,可以利用cookie,设置Domain为".a.com'即可,这里就不再赘叙。

2、完成跨域单点登录。如 http://www.a.com/   http://www.b.com/ 这2个站点之间实现共享一个身份验证系统,只需在一处地方登录,下面主要谈下这种方式的实现方法。 

asp.net 跨域单点登录实现原理:

当用户第一次访问web应用系统1的时候,因为还没有登录,会被引导到认证中心进行登录;根据用户提供的登录信息,认证系统进行身份效验,如果
通过效验,返回给用户一个认证的凭据;用户再访问别的web应用的时候就会将这个Token带上,作为自己认证的凭据,应用系统接受到请求之后会把Token送到认证中心进行效验,检查Token的合法性。如果通过效验,用户就可以在不用再次登录的情况下访问应用系统2和应用系统3了。所有应用系统共享一个身份认证系统。认证系统的主要功能是将用户的登录信息和用户信息库相比较,对用户进行登录认证;认证成功后,认证系统应该生成统一的认证标志,返还给用户。另外,认证系统还应该对Token进行效验,判断其有效性。 所有应用系统能够识别和提取Token信息要实现SSO的功能,让用户只登录一次,就必须让应用系统能够识别已经登录过的用户。应用系统应该能对Token进行识别和提取,通过与认证系统的通讯,能自动判断当前用户是否登录过,从而完成单点登录的功能。

比如说,我现在有3个分站点和1个认证中心(总站)。当用户访问分站点的时候,分站点会发Token到验证中心进行验证。验证中心判断用户是否已经登录。如果未登录,则返回到验证中心登录入口进行登录,否之则返回Token验证到分站点,直接进入分站点。


如图所示:

单点登录流程图

 

上面是实现单点登录的原理图,下面介绍下如何用asp.net实现跨域单点登录:

一、新建网站 MasterSite,作为总站认证中心。配置web.config,采用form登录验证。
      配置如下:

     

  1. <authentication mode="Forms">  
  2.   <forms name=".AspxFormAuth" loginUrl="Default.aspx" defaultUrl="center.html" protection="All" path="/" timeout="120">  
  3.   </forms>  
  4. </authentication>  
  5. <authorization>  
  6.     <!--拒绝所有匿名用户-->  
  7.     <deny users="?"/>  
  8. </authorization>  

 

 

      添加Default.aspx页面,用来进行登录。代码如下:
   

     HTML Code:

    

  1. <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>   
  2.   
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">   
  4.   
  5. <html xmlns="http://www.w3.org/1999/xhtml" >   
  6. <head runat="server">   
  7.     <title>总站登录</title>   
  8. </head>   
  9. <body>   
  10.     <form id="form1" runat="server">   
  11.     <div>   
  12.         <asp:Login ID="Login1" runat="server" OnAuthenticate="Login1_Authenticate" UserName="test">   
  13.         </asp:Login>   
  14.     </div>   
  15.     </form>   
  16. </body>   
  17. </html>  

 


   Default.cs Code:

  

  1. using System;   
  2. using System.Data;   
  3. using System.Configuration;   
  4. using System.Web;   
  5. using System.Web.Security;   
  6. using System.Web.UI;   
  7. using System.Web.UI.WebControls;   
  8. using System.Web.UI.WebControls.WebParts;   
  9. using System.Web.UI.HtmlControls;   
  10. using System.Text;   
  11.   
  12. public partial class _Default : System.Web.UI.Page    
  13. {   
  14.     protected void Page_Load(object sender, EventArgs e)   
  15.     {   
  16.         if (!IsPostBack)   
  17.         {   
  18.             SSORequest ssoRequest = new SSORequest();  
  19.  
  20.  
  21.             #region 验证 Post 过来的参数   
  22.             //--------------------------------   
  23.             // 请求注销   
  24.             if (!string.IsNullOrEmpty(Request["Logout"]))   
  25.             {   
  26.                 Authentication.Logout();   
  27.                 return;   
  28.             }   
  29.             //--------------------------------   
  30.             // 各独立站点标识   
  31.             if (string.IsNullOrEmpty(Request["IASID"]))   
  32.             {   
  33.                 return;   
  34.             }   
  35.             else  
  36.             {   
  37.                 ssoRequest.IASID = Request["IASID"];   
  38.             }   
  39.   
  40.             //--------------------------------   
  41.             // 时间戳   
  42.             if (string.IsNullOrEmpty(Request["TimeStamp"]))   
  43.             {   
  44.                 return;   
  45.             }   
  46.             else  
  47.             {   
  48.                 ssoRequest.TimeStamp = Request["TimeStamp"];   
  49.             }   
  50.   
  51.             //--------------------------------   
  52.             // 各独立站点的访问地址   
  53.             if (string.IsNullOrEmpty(Request["AppUrl"]))   
  54.             {   
  55.                 return;   
  56.             }   
  57.             else  
  58.             {   
  59.                 ssoRequest.AppUrl = Request["AppUrl"];   
  60.             }   
  61.   
  62.             //--------------------------------   
  63.             // 各独立站点的 Token   
  64.             if (string.IsNullOrEmpty(Request["Authenticator"]))   
  65.             {   
  66.                 return;   
  67.             }   
  68.             else  
  69.             {   
  70.                 ssoRequest.Authenticator = Request["Authenticator"];   
  71.             }   
  72.   
  73.             ViewState["SSORequest"] = ssoRequest;  
  74.  
  75.             #endregion   
  76.   
  77.   
  78.             //验证从分站发过来的Token   
  79.             if (Authentication.ValidateAppToken(ssoRequest))   
  80.             {   
  81.                 string userAccount = null;   
  82.   
  83.                 // 验证用户之前是否登录过   
  84.                 //验证 EAC 认证中心的 Cookie,验证通过时获取用户登录账号   
  85.                 if (Authentication.ValidateEACCookie(out userAccount))   
  86.                 {   
  87.                     ssoRequest.UserAccount = userAccount;   
  88.   
  89.                     //创建认证中心发往各分站的 Token   
  90.                     if (Authentication.CreateEACToken(ssoRequest))   
  91.                     {   
  92.                         Post(ssoRequest);   
  93.                     }   
  94.                 }   
  95.                 else  
  96.                 {   
  97.                     return;   
  98.                 }   
  99.             }   
  100.             else  
  101.             {   
  102.                 return;   
  103.             }   
  104.         }   
  105.     }   
  106.   
  107.   
  108.     //post请求   
  109.     void Post(SSORequest ssoRequest)   
  110.     {   
  111.         PostService ps = new PostService();   
  112.   
  113.         ps.Url = ssoRequest.AppUrl;   
  114.   
  115.         ps.Add("UserAccount", ssoRequest.UserAccount);   
  116.         ps.Add("IASID", ssoRequest.IASID);   
  117.         ps.Add("TimeStamp", ssoRequest.TimeStamp);   
  118.         ps.Add("AppUrl", ssoRequest.AppUrl);   
  119.         ps.Add("Authenticator", ssoRequest.Authenticator);   
  120.   
  121.         ps.Post();   
  122.     }   
  123.   
  124.     /// <summary>   
  125.     /// 验证登录账号和密码是否正确   
  126.     /// </summary>   
  127.     /// <param name="userName">登录账号</param>   
  128.     /// <param name="userPwd">登录密码</param>   
  129.     /// <returns></returns>   
  130.     private bool ValidateUserInfo(string userName, string userPwd)   
  131.     {   
  132.         //从数据库中读取,验证登录账号和密码   
  133.         //略...   
  134.         return true;   
  135.     }   
  136.   
  137.     protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)   
  138.     {   
  139.         if (string.IsNullOrEmpty(Login1.UserName) || string.IsNullOrEmpty(Login1.Password))   
  140.         {   
  141.             Page.RegisterClientScriptBlock("Add""<mce:script lanuage=\"javascript\"><!--   
  142. alert('用户名密码不能为空!');   
  143. // --></mce:script>");   
  144.             return;   
  145.         }   
  146.         else if (ValidateUserInfo(Login1.UserName, Login1.Password) == false)   
  147.         {   
  148.             Page.RegisterClientScriptBlock("Add""<mce:script lanuage=\"javascript\"><!--   
  149. alert('用户名密码错误!');   
  150. // --></mce:script>");   
  151.             return;   
  152.         }   
  153.         else  
  154.         {   
  155.             Session["CurrUserName"] = Login1.UserName;   
  156.             Session.Timeout = 120;   
  157.   
  158.             SSORequest ssoRequest = ViewState["SSORequest"as SSORequest;   
  159.   
  160.             // 如果不是从各分站 Post 过来的请求,则默认登录主站   
  161.             if (ssoRequest == null)   
  162.             {   
  163.                 FormsAuthentication.SetAuthCookie(Login1.UserName, false);   
  164.   
  165.                 ssoRequest = new SSORequest();   
  166.                 //主站标识ID   
  167.                 ssoRequest.IASID = "00";   
  168.                 ssoRequest.AppUrl = "SiteList.aspx";   
  169.                 ssoRequest.TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm");   
  170.                 ssoRequest.Authenticator = string.Empty;   
  171.   
  172.                 Response.Redirect("SiteList.aspx");   
  173.             }   
  174.             ssoRequest.UserAccount = Login1.UserName;   
  175.   
  176.             //创建Token   
  177.             if (Authentication.CreateEACToken(ssoRequest))   
  178.             {   
  179.                 string expireTime = DateTime.Now.AddHours(3).ToString("yyyy-MM-dd HH:mm");   
  180.   
  181.                 Authentication.CreatEACCookie(ssoRequest.UserAccount, ssoRequest.TimeStamp, expireTime);   
  182.   
  183.                 Post(ssoRequest);   
  184.             }   
  185.   
  186.         }   
  187.     }   
  188.   
  189.        
  190. }  

 

  代码说明:验证分站post过来的Token请求,如果用户已经登录,则创建认证中心发往各分站的 Token验证,转向分站,否之则返回登录。若是直接登录主站则转向站点选择页面sitelist.aspx,选择你要登录的分站点。

如图:

主站登录

选择站点

二、新建站点1,代码如下:

HTML Code:

  1. <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>   
  2.   
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">   
  4.   
  5. <html xmlns="http://www.w3.org/1999/xhtml" >   
  6. <head runat="server">   
  7.     <title> 站点一</title>   
  8. </head>   
  9. <body>   
  10.     <form id="form1" runat="server">   
  11.     <div>   
  12.         <br />   
  13.         <br />   
  14.         <asp:LinkButton ID="LinkButton1" runat="server" OnClick="LinkButton1_Click">返回主站</asp:LinkButton>   
  15.              
  16.         <asp:LinkButton ID="LinkButton2" runat="server" OnClick="LinkButton2_Click">注销登录</asp:LinkButton></div>   
  17.     </form>   
  18. </body>   
  19. </html>  

 

Default.cs code:

  1. using System;   
  2. using System.Data;   
  3. using System.Configuration;   
  4. using System.Web;   
  5. using System.Web.Security;   
  6. using System.Web.UI;   
  7. using System.Web.UI.WebControls;   
  8. using System.Web.UI.WebControls.WebParts;   
  9. using System.Web.UI.HtmlControls;   
  10. using System.Text;   
  11.   
  12. public partial class _Default : System.Web.UI.Page    
  13. {   
  14.     protected void Page_Load(object sender, EventArgs e)   
  15.     {   
  16.         if (!IsPostBack)   
  17.         {  
  18.             #region SSO 部分代码   
  19.             SSORequest ssoRequest = new SSORequest();   
  20.   
  21.             if (string.IsNullOrEmpty(Request["IASID"]))   
  22.             {   
  23.                 ssoRequest.IASID = "01";   
  24.                 ssoRequest.TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm");   
  25.                 ssoRequest.AppUrl = Request.Url.ToString();   
  26.                 Authentication.CreateAppToken(ssoRequest);   
  27.   
  28.                 Post(ssoRequest);   
  29.             }   
  30.             else if (!string.IsNullOrEmpty(Request["IASID"])   
  31.                 && !string.IsNullOrEmpty(Request["TimeStamp"])   
  32.                 && !string.IsNullOrEmpty(Request["AppUrl"])   
  33.                 && !string.IsNullOrEmpty(Request["UserAccount"])   
  34.                 && !string.IsNullOrEmpty(Request["Authenticator"]))   
  35.             {   
  36.                 ssoRequest.IASID = Request["IASID"];   
  37.                 ssoRequest.TimeStamp = Request["TimeStamp"];   
  38.                 ssoRequest.AppUrl = Request["AppUrl"];   
  39.                 ssoRequest.UserAccount = Request["UserAccount"];   
  40.                 ssoRequest.Authenticator = Request["Authenticator"];   
  41.   
  42.                 if (Authentication.ValidateEACToken(ssoRequest))   
  43.                 {   
  44.                     //从数据库中获取UserId   
  45.                     Session["CurrUserName"] = Request["UserAccount"];   
  46.                     Session.Timeout = 120;   
  47.                     FormsAuthentication.SetAuthCookie(Request["UserAccount"], false);   
  48.                     Response.Write(string.Format("{0},您好!欢迎来到site1,  >> 访问<a href="\" mce_href="\""http://localhost/Site2/Default.aspx\">site2</a>",ssoRequest.UserAccount));   
  49.                 }   
  50.             }   
  51.   
  52.             ViewState["SSORequest"] = ssoRequest;  
  53.  
  54.             #endregion   
  55.         }   
  56.     }   
  57.   
  58.     void Post(SSORequest ssoRequest)   
  59.     {   
  60.         PostService ps = new PostService();   
  61.         //认证中心(主站)地址   
  62.         string EACUrl = "http://localhost/MasterSite/Default.aspx";   
  63.         ps.Url = EACUrl;   
  64.         //ps.Add("UserAccount", ssoRequest.UserAccount);   
  65.         ps.Add("IASID", ssoRequest.IASID);   
  66.         ps.Add("TimeStamp", ssoRequest.TimeStamp);   
  67.         ps.Add("AppUrl", ssoRequest.AppUrl);   
  68.         ps.Add("Authenticator", ssoRequest.Authenticator);   
  69.   
  70.         ps.Post();   
  71.     }   
  72.   
  73.   
  74.     //注销登录   
  75.     protected void LinkButton2_Click(object sender, EventArgs e)   
  76.     {   
  77.         FormsAuthentication.SignOut();   
  78.   
  79.         SSORequest ssoRequest = new SSORequest();   
  80.   
  81.         ssoRequest.IASID = "01";   
  82.         ssoRequest.TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm");   
  83.         ssoRequest.AppUrl = Request.Url.ToString();   
  84.   
  85.         Authentication.CreateAppToken(ssoRequest);   
  86.   
  87.         PostService ps = new PostService();   
  88.   
  89.         //认证中心(主站)地址   
  90.         string EACUrl = "http://localhost/MasterSite/Default.aspx";   
  91.         ps.Url = EACUrl;   
  92.   
  93.         ps.Add("IASID", ssoRequest.IASID);   
  94.         ps.Add("TimeStamp", ssoRequest.TimeStamp);   
  95.         ps.Add("AppUrl", ssoRequest.AppUrl);   
  96.         ps.Add("Authenticator", ssoRequest.Authenticator);   
  97.   
  98.         ps.Add("Logout""true");   
  99.   
  100.         ps.Post();   
  101.     }   
  102.   
  103.     //返回主站   
  104.     protected void LinkButton1_Click(object sender, EventArgs e)   
  105.     {   
  106.         if (Session["CurrUserName"] != null)   
  107.         {   
  108.             Response.Redirect("http://localhost/MasterSite/SiteList.aspx");   
  109.         }   
  110.     }   
  111. }  

 

配置web.config

  1. <authentication mode="Forms">   
  2.             <forms name=".AspxFormAuth" loginUrl="Default.aspx" defaultUrl="center.html" protection="All" path="/" timeout="60">   
  3.             </forms>   
  4.         </authentication>   
  5.         <authorization>   
  6.             <!--拒绝所有匿名用户-->   
  7.             <deny users="?"/>   
  8.         </authorization>  

 

三、同二一样,新建站点Site2,代码如下:

  1. using System;   
  2. using System.Data;   
  3. using System.Configuration;   
  4. using System.Web;   
  5. using System.Web.Security;   
  6. using System.Web.UI;   
  7. using System.Web.UI.WebControls;   
  8. using System.Web.UI.WebControls.WebParts;   
  9. using System.Web.UI.HtmlControls;   
  10.   
  11. public partial class _Default : System.Web.UI.Page   
  12. {   
  13.     protected void Page_Load(object sender, EventArgs e)   
  14.     {   
  15.         if (!IsPostBack)   
  16.         {  
  17.             #region SSO 部分代码   
  18.             SSORequest ssoRequest = new SSORequest();   
  19.   
  20.             if (string.IsNullOrEmpty(Request["IASID"]))   
  21.             {   
  22.                 ssoRequest.IASID = "02";   
  23.                 ssoRequest.TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm");   
  24.                 ssoRequest.AppUrl = Request.Url.ToString();   
  25.                 Authentication.CreateAppToken(ssoRequest);   
  26.   
  27.                 Post(ssoRequest);   
  28.             }   
  29.             else if (!string.IsNullOrEmpty(Request["IASID"])   
  30.                 && !string.IsNullOrEmpty(Request["TimeStamp"])   
  31.                 && !string.IsNullOrEmpty(Request["AppUrl"])   
  32.                 && !string.IsNullOrEmpty(Request["UserAccount"])   
  33.                 && !string.IsNullOrEmpty(Request["Authenticator"]))   
  34.             {   
  35.                 ssoRequest.IASID = Request["IASID"];   
  36.                 ssoRequest.TimeStamp = Request["TimeStamp"];   
  37.                 ssoRequest.AppUrl = Request["AppUrl"];   
  38.                 ssoRequest.UserAccount = Request["UserAccount"];   
  39.                 ssoRequest.Authenticator = Request["Authenticator"];   
  40.   
  41.                 if (Authentication.ValidateEACToken(ssoRequest))   
  42.                 {   
  43.                     Session["CurrUserName"] = Request["UserAccount"];   
  44.                     Session.Timeout = 120;   
  45.                     FormsAuthentication.SetAuthCookie(Request["UserAccount"], false);   
  46.                     Response.Write(string.Format("{0},您好!欢迎来到site2,  >> 访问<a href="\" mce_href="\""http://localhost/Site1/Default.aspx\">site1</a>", ssoRequest.UserAccount));   
  47.                 }   
  48.             }   
  49.   
  50.             ViewState["SSORequest"] = ssoRequest;  
  51.  
  52.             #endregion   
  53.         }   
  54.     }   
  55.   
  56.     void Post(SSORequest ssoRequest)   
  57.     {   
  58.         PostService ps = new PostService();   
  59.         //认证中心(主站)地址   
  60.         string EACUrl = "http://localhost/MasterSite/Default.aspx";   
  61.         ps.Url = EACUrl;   
  62.         //ps.Add("UserAccount", ssoRequest.UserAccount);   
  63.         ps.Add("IASID", ssoRequest.IASID);   
  64.         ps.Add("TimeStamp", ssoRequest.TimeStamp);   
  65.         ps.Add("AppUrl", ssoRequest.AppUrl);   
  66.         ps.Add("Authenticator", ssoRequest.Authenticator);   
  67.   
  68.         ps.Post();   
  69.     }   
  70.   
  71.   
  72.     //注销登录   
  73.     protected void LinkButton2_Click(object sender, EventArgs e)   
  74.     {   
  75.         FormsAuthentication.SignOut();   
  76.   
  77.         SSORequest ssoRequest = new SSORequest();   
  78.   
  79.         ssoRequest.IASID = "02";   
  80.         ssoRequest.TimeStamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm");   
  81.         ssoRequest.AppUrl = Request.Url.ToString();   
  82.   
  83.         Authentication.CreateAppToken(ssoRequest);   
  84.   
  85.         PostService ps = new PostService();   
  86.   
  87.         //认证中心(主站)地址   
  88.         string EACUrl = "http://localhost/MasterSite/Default.aspx";   
  89.         ps.Url = EACUrl;   
  90.   
  91.         ps.Add("IASID", ssoRequest.IASID);   
  92.         ps.Add("TimeStamp", ssoRequest.TimeStamp);   
  93.         ps.Add("AppUrl", ssoRequest.AppUrl);   
  94.         ps.Add("Authenticator", ssoRequest.Authenticator);   
  95.   
  96.         ps.Add("Logout""true");   
  97.   
  98.         ps.Post();   
  99.     }   
  100.   
  101.     //返回主站   
  102.     protected void LinkButton1_Click(object sender, EventArgs e)   
  103.     {   
  104.         if (Session["CurrUserName"] != null)   
  105.         {   
  106.             Response.Redirect("http://localhost/MasterSite/SiteList.aspx");   
  107.         }   
  108.     }   
  109. }  

 

对于tokent请求,tokent验证,需要对它进行加密、解密。

其它代码:

Authentication.cs

  1. using System;   
  2. using System.Data;   
  3. using System.Configuration;   
  4. using System.Web;   
  5. using System.Web.Security;   
  6. using System.Collections.Generic;   
  7. using System.Text;   
  8.   
  9. /// <summary>   
  10. /// 安全验证类   
  11. /// </summary>   
  12. public class Authentication   
  13. {   
  14.     static readonly string cookieName = "EACToken";   
  15.     static readonly string hashSplitter = "|";   
  16.   
  17.     public Authentication()   
  18.     {   
  19.     }   
  20.   
  21.     public static string GetAppKey(int appID)   
  22.     {   
  23.         //string cmdText = @"select * from ";   
  24.         return string.Empty;   
  25.     }   
  26.   
  27.     public static string GetAppKey()   
  28.     {   
  29.         return "22362E7A9285DD53A0BBC2932F9733C505DC04EDBFE00D70";   
  30.     }   
  31.   
  32.     public static string GetAppIV()   
  33.     {   
  34.         return "1E7FA9231E7FA923";   
  35.     }   
  36.   
  37.     /// <summary>   
  38.     /// 取得加密服务   
  39.     /// </summary>   
  40.     /// <returns></returns>   
  41.     static CryptoService GetCryptoService()   
  42.     {   
  43.         string key = GetAppKey();   
  44.         string IV = GetAppIV();   
  45.   
  46.         CryptoService cs = new CryptoService(key, IV);   
  47.         return cs;   
  48.     }   
  49.   
  50.     /// <summary>   
  51.     /// 创建各分站发往认证中心的 Token   
  52.     /// </summary>   
  53.     /// <param name="ssoRequest"></param>   
  54.     /// <returns></returns>   
  55.     public static bool CreateAppToken(SSORequest ssoRequest)   
  56.     {   
  57.         string OriginalAuthenticator = ssoRequest.IASID + ssoRequest.TimeStamp + ssoRequest.AppUrl;   
  58.         string AuthenticatorDigest = CryptoHelper.ComputeHashString(OriginalAuthenticator);   
  59.         string sToEncrypt = OriginalAuthenticator + AuthenticatorDigest;   
  60.         byte[] bToEncrypt = CryptoHelper.ConvertStringToByteArray(sToEncrypt);   
  61.   
  62.         CryptoService cs = GetCryptoService();   
  63.   
  64.         byte[] encrypted;   
  65.   
  66.         if (cs.Encrypt(bToEncrypt, out encrypted))   
  67.         {   
  68.             ssoRequest.Authenticator = CryptoHelper.ToBase64String(encrypted);   
  69.   
  70.             return true;   
  71.         }   
  72.         else  
  73.         {   
  74.             return false;   
  75.         }   
  76.     }   
  77.   
  78.   
  79.     /// <summary>   
  80.     /// 验证从各分站发送过来的 Token   
  81.     /// </summary>   
  82.     /// <param name="ssoRequest"></param>   
  83.     /// <returns></returns>   
  84.     public static bool ValidateAppToken(SSORequest ssoRequest)   
  85.     {   
  86.         string Authenticator = ssoRequest.Authenticator;   
  87.   
  88.         string OriginalAuthenticator = ssoRequest.IASID + ssoRequest.TimeStamp + ssoRequest.AppUrl;   
  89.         string AuthenticatorDigest = CryptoHelper.ComputeHashString(OriginalAuthenticator);   
  90.         string sToEncrypt = OriginalAuthenticator + AuthenticatorDigest;   
  91.         byte[] bToEncrypt = CryptoHelper.ConvertStringToByteArray(sToEncrypt);   
  92.   
  93.         CryptoService cs = GetCryptoService();   
  94.         byte[] encrypted;   
  95.   
  96.         if (cs.Encrypt(bToEncrypt, out encrypted))   
  97.         {   
  98.             return Authenticator == CryptoHelper.ToBase64String(encrypted);   
  99.         }   
  100.         else  
  101.         {   
  102.             return false;   
  103.         }   
  104.     }   
  105.   
  106.   
  107.     /// <summary>   
  108.     /// 创建认证中心发往各分站的 Token   
  109.     /// </summary>   
  110.     /// <param name="ssoRequest"></param>   
  111.     /// <returns></returns>   
  112.     public static bool CreateEACToken(SSORequest ssoRequest)   
  113.     {   
  114.         string OriginalAuthenticator = ssoRequest.UserAccount + ssoRequest.IASID + ssoRequest.TimeStamp + ssoRequest.AppUrl;   
  115.         string AuthenticatorDigest = CryptoHelper.ComputeHashString(OriginalAuthenticator);   
  116.         string sToEncrypt = OriginalAuthenticator + AuthenticatorDigest;   
  117.         byte[] bToEncrypt = CryptoHelper.ConvertStringToByteArray(sToEncrypt);   
  118.   
  119.         CryptoService cs = GetCryptoService();   
  120.         byte[] encrypted;   
  121.   
  122.         if (cs.Encrypt(bToEncrypt, out encrypted))   
  123.         {   
  124.             ssoRequest.Authenticator = CryptoHelper.ToBase64String(encrypted);   
  125.   
  126.             return true;   
  127.         }   
  128.         else  
  129.         {   
  130.             return false;   
  131.         }   
  132.     }   
  133.   
  134.   
  135.     /// <summary>   
  136.     /// 验证从认证中心发送过来的 Token   
  137.     /// </summary>   
  138.     /// <param name="ssoRequest"></param>   
  139.     /// <returns></returns>   
  140.     public static bool ValidateEACToken(SSORequest ssoRequest)   
  141.     {   
  142.         string Authenticator = ssoRequest.Authenticator;   
  143.   
  144.         string OriginalAuthenticator = ssoRequest.UserAccount + ssoRequest.IASID + ssoRequest.TimeStamp + ssoRequest.AppUrl;   
  145.         string AuthenticatorDigest = CryptoHelper.ComputeHashString(OriginalAuthenticator);   
  146.         string sToEncrypt = OriginalAuthenticator + AuthenticatorDigest;   
  147.         byte[] bToEncrypt = CryptoHelper.ConvertStringToByteArray(sToEncrypt);   
  148.   
  149.         string EncryCurrentAuthenticator = string.Empty;   
  150.         CryptoService cs = GetCryptoService();   
  151.         byte[] encrypted;   
  152.   
  153.         if (cs.Encrypt(bToEncrypt, out encrypted))   
  154.         {   
  155.             EncryCurrentAuthenticator = CryptoHelper.ToBase64String(encrypted);   
  156.   
  157.             return Authenticator == EncryCurrentAuthenticator;   
  158.         }   
  159.         else  
  160.         {   
  161.             return false;   
  162.         }   
  163.     }   
  164.   
  165.   
  166.     /// <summary>   
  167.     /// 创建 EAC 认证中心的 Cookie   
  168.     /// </summary>   
  169.     /// <param name="userAccount"></param>   
  170.     /// <param name="timeStamp"></param>   
  171.     /// <param name="expireTime"></param>   
  172.     /// <param name="cookieValue"></param>   
  173.     /// <returns></returns>   
  174.     public static bool CreatEACCookie(string userAccount, string timeStamp, string expireTime)   
  175.     {   
  176.         string plainText = "UserAccount=" + userAccount + ";TimeStamp=" + timeStamp + ";ExpireTime=" + expireTime;   
  177.         plainText += hashSplitter + CryptoHelper.ComputeHashString(plainText);   
  178.   
  179.         CryptoService cs = GetCryptoService();   
  180.         byte[] encrypted;   
  181.   
  182.         if (cs.Encrypt(CryptoHelper.ConvertStringToByteArray(plainText), out encrypted))   
  183.         {   
  184.             string cookieValue = CryptoHelper.ToBase64String(encrypted);   
  185.             SetCookie(cookieValue);   
  186.   
  187.             return true;   
  188.         }   
  189.         else  
  190.         {   
  191.             return false;   
  192.         }   
  193.     }   
  194.   
  195.     /// <summary>   
  196.     /// 验证 EAC 认证中心的 Cookie,验证通过时获取用户登录账号   
  197.     /// </summary>   
  198.     /// <param name="userAccount">输出用户登录账号</param>   
  199.     /// <returns></returns>   
  200.     public static bool ValidateEACCookie(out string userAccount)   
  201.     {   
  202.         userAccount = string.Empty;   
  203.         try  
  204.         {   
  205.   
  206.             string cookieValue = GetCookie().Value;   
  207.             byte[] toDecrypt = CryptoHelper.FromBase64String(cookieValue);   
  208.             CryptoService cs = GetCryptoService();   
  209.   
  210.             string decrypted = string.Empty;   
  211.             if (cs.Decrypt(toDecrypt, out decrypted))   
  212.             {   
  213.   
  214.                 string[] arrTemp = decrypted.Split(Convert.ToChar(hashSplitter));   
  215.                 string plainText = arrTemp[0];   
  216.                 string hashedText = arrTemp[1];   
  217.   
  218.                 userAccount = plainText.Split(Convert.ToChar(";"))[0].Split(Convert.ToChar("="))[1];   
  219.   
  220.                 return hashedText.Replace("\0"string.Empty) == CryptoHelper.ComputeHashString(plainText);   
  221.   
  222.             }   
  223.             else  
  224.             {   
  225.                 return false;   
  226.             }   
  227.         }   
  228.         catch (Exception e)   
  229.         {   
  230.             return false;   
  231.         }   
  232.     }   
  233.   
  234.   
  235.     public static void Logout()   
  236.     {   
  237.         HttpContext.Current.Response.Cookies[cookieName].Expires = DateTime.Parse("1900-1-1");   
  238.         HttpContext.Current.Response.Cookies[cookieName].Path = "/";   
  239.     }   
  240.   
  241.     private static void SetCookie(string cookieValue)   
  242.     {   
  243.         HttpContext.Current.Response.Cookies[cookieName].Value = cookieValue;   
  244.         HttpContext.Current.Response.Cookies[cookieName].Expires = DateTime.Now.AddHours(24);   
  245.         HttpContext.Current.Response.Cookies[cookieName].Path = "/";   
  246.     }   
  247.   
  248.     private static HttpCookie GetCookie()   
  249.     {   
  250.         HttpCookie cookie = HttpContext.Current.Request.Cookies["EACToken"];   
  251.         return cookie;   
  252.     }   
  253. }  

 

CryptoHelper.cs

 

  1. using System;   
  2. using System.Collections.Generic;   
  3. using System.Text;   
  4. using System.Security.Cryptography;   
  5.   
  6. public class CryptoHelper   
  7. {   
  8.     /// <summary>   
  9.     /// 复合 Hash:string --> byte[] --> hashed byte[] --> base64 string   
  10.     /// </summary>   
  11.     /// <param name="s"></param>   
  12.     /// <returns></returns>   
  13.     public static string ComputeHashString(string s)   
  14.     {   
  15.         return ToBase64String(ComputeHash(ConvertStringToByteArray(s)));   
  16.     }   
  17.   
  18.   
  19.     public static byte[] ComputeHash(byte[] buf)   
  20.     {   
  21.         //return ((HashAlgorithm)CryptoConfig.CreateFromName("SHA1")).ComputeHash(buf);   
  22.         return SHA1.Create().ComputeHash(buf);   
  23.   
  24.     }   
  25.   
  26.     /// <summary>   
  27.     /// //System.Convert.ToBase64String   
  28.     /// </summary>   
  29.     /// <param name="buf"></param>   
  30.     /// <returns></returns>   
  31.     public static string ToBase64String(byte[] buf)   
  32.     {   
  33.         return System.Convert.ToBase64String(buf);   
  34.     }   
  35.   
  36.   
  37.     public static byte[] FromBase64String(string s)   
  38.     {   
  39.         return System.Convert.FromBase64String(s);   
  40.     }   
  41.   
  42.     /// <summary>   
  43.     /// //Encoding.UTF8.GetBytes(s)   
  44.     /// </summary>   
  45.     /// <param name="s"></param>   
  46.     /// <returns></returns>   
  47.     public static byte[] ConvertStringToByteArray(String s)   
  48.     {   
  49.         return Encoding.UTF8.GetBytes(s);//gb2312   
  50.     }   
  51.   
  52.   
  53.     public static string ConvertByteArrayToString(byte[] buf)   
  54.     {   
  55.         //return System.Text.Encoding.GetEncoding("utf-8").GetString(buf);   
  56.   
  57.         return Encoding.UTF8.GetString(buf);   
  58.     }   
  59.   
  60.   
  61.     /// <summary>   
  62.     /// 字节数组转换为十六进制字符串   
  63.     /// </summary>   
  64.     /// <param name="buf"></param>   
  65.     /// <returns></returns>   
  66.     public static string ByteArrayToHexString(byte[] buf)   
  67.     {   
  68.         StringBuilder sb = new StringBuilder();   
  69.         for (int i = 0; i < buf.Length; i++)   
  70.         {   
  71.             sb.Append(buf[i].ToString("X").Length == 2 ? buf[i].ToString("X") : "0" + buf[i].ToString("X"));   
  72.         }   
  73.         return sb.ToString();   
  74.     }   
  75.   
  76.     /// <summary>   
  77.     /// 十六进制字符串转换为字节数组   
  78.     /// </summary>   
  79.     /// <param name="s"></param>   
  80.     /// <returns></returns>   
  81.     public static byte[] HexStringToByteArray(string s)   
  82.     {   
  83.         Byte[] buf = new byte[s.Length / 2];   
  84.         for (int i = 0; i < buf.Length; i++)   
  85.         {   
  86.             buf[i] = (byte)(Char2Hex(s.Substring(i * 2, 1)) * 0x10 + Char2Hex(s.Substring(i * 2 + 1, 1)));   
  87.         }   
  88.         return buf;   
  89.     }   
  90.   
  91.   
  92.     private static byte Char2Hex(string chr)   
  93.     {   
  94.         switch (chr)   
  95.         {   
  96.             case "0":   
  97.                 return 0x00;   
  98.             case "1":   
  99.                 return 0x01;   
  100.             case "2":   
  101.                 return 0x02;   
  102.             case "3":   
  103.                 return 0x03;   
  104.             case "4":   
  105.                 return 0x04;   
  106.             case "5":   
  107.                 return 0x05;   
  108.             case "6":   
  109.                 return 0x06;   
  110.             case "7":   
  111.                 return 0x07;   
  112.             case "8":   
  113.                 return 0x08;   
  114.             case "9":   
  115.                 return 0x09;   
  116.             case "A":   
  117.                 return 0x0a;   
  118.             case "B":   
  119.                 return 0x0b;   
  120.             case "C":   
  121.                 return 0x0c;   
  122.             case "D":   
  123.                 return 0x0d;   
  124.             case "E":   
  125.                 return 0x0e;   
  126.             case "F":   
  127.                 return 0x0f;   
  128.         }   
  129.         return 0x00;   
  130.     }   
  131. }  

 

CryptoService.cs

 

  1. using System;   
  2. using System.Data;   
  3. using System.Configuration;   
  4. using System.Web;   
  5. using System.Web.Security;   
  6. using System.Web.UI;   
  7. using System.Web.UI.WebControls;   
  8. using System.Web.UI.WebControls.WebParts;   
  9. using System.Web.UI.HtmlControls;   
  10. using System.Text;   
  11. using System.Security.Cryptography;   
  12. using System.IO;   
  13.   
  14. public class CryptoService   
  15. {   
  16.     /// <summary>   
  17.     /// 加密的密钥   
  18.     /// </summary>   
  19.     string sKey = "22362E7A9285DD53A0BBC2932F9733C505DC04EDBFE00D70";   
  20.     string sIV = "1E7FA9231E7FA923";   
  21.   
  22.     byte[] byteKey;   
  23.     byte[] byteIV;   
  24.   
  25.     /// <summary>   
  26.     /// 加密向量   
  27.     /// </summary>   
  28.     static byte[] bIV ={ 1, 2, 3, 4, 5, 6, 7, 8 };   
  29.   
  30.     public CryptoService()   
  31.     { }   
  32.   
  33.     public CryptoService(string key, string IV)   
  34.     {   
  35.         sKey = key;   
  36.         sIV = IV;   
  37.   
  38.         byteKey = CryptoHelper.HexStringToByteArray(sKey);   
  39.         byteIV = CryptoHelper.HexStringToByteArray(sIV);   
  40.     }   
  41.   
  42.   
  43.   
  44.     /// <summary>   
  45.     /// 将明文加密,返回密文   
  46.     /// </summary>   
  47.     /// <param name="Data">要加密的字串</param>   
  48.     /// <returns></returns>   
  49.     public byte[] Encrypt(string Data)   
  50.     {   
  51.         try  
  52.         {   
  53.             byte[] ret;   
  54.   
  55.             using (MemoryStream mStream = new MemoryStream())   
  56.             using (CryptoStream cStream = new CryptoStream(mStream,   
  57.                 new TripleDESCryptoServiceProvider().CreateEncryptor(byteKey, byteIV),   
  58.                 CryptoStreamMode.Write))   
  59.             {   
  60.   
  61.                 byte[] toEncrypt = new ASCIIEncoding().GetBytes(Data);   
  62.   
  63.                 // Write the byte array to the crypto stream and flush it.   
  64.                 cStream.Write(toEncrypt, 0, toEncrypt.Length);   
  65.                 cStream.FlushFinalBlock();   
  66.   
  67.                 // Get an array of bytes from the    
  68.                 // MemoryStream that holds the    
  69.                 // encrypted data.   
  70.                 ret = mStream.ToArray();   
  71.   
  72.             }   
  73.   
  74.             return ret;   
  75.         }   
  76.         catch (CryptographicException e)   
  77.         {   
  78.             //Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);   
  79.             return null;   
  80.         }   
  81.   
  82.     }   
  83.   
  84.   
  85.     /// <summary>   
  86.     /// 将明文加密,返回密文   
  87.     /// </summary>   
  88.     /// <param name="toEncrypt">明文</param>   
  89.     /// <param name="encrypted">密文</param>   
  90.     /// <returns></returns>   
  91.     public bool Encrypt(byte[] toEncrypt, out byte[] encrypted)   
  92.     {   
  93.         encrypted = null;   
  94.         try  
  95.         {   
  96.             // Create a new MemoryStream using the passed    
  97.             // array of encrypted data.   
  98.             // Create a CryptoStream using the MemoryStream    
  99.             // and the passed key and initialization vector (IV).   
  100.             using (MemoryStream mStream = new MemoryStream())   
  101.             using (CryptoStream cStream = new CryptoStream(mStream,   
  102.                 new TripleDESCryptoServiceProvider().CreateEncryptor(byteKey, byteIV),   
  103.                 CryptoStreamMode.Write))   
  104.             {   
  105.   
  106.                 // Write the byte array to the crypto stream and flush it.   
  107.                 cStream.Write(toEncrypt, 0, toEncrypt.Length);   
  108.                 cStream.FlushFinalBlock();   
  109.   
  110.                 // Get an array of bytes from the    
  111.                 // MemoryStream that holds the    
  112.                 // encrypted data.   
  113.                 encrypted = mStream.ToArray();   
  114.             }   
  115.   
  116.             return true;   
  117.         }   
  118.         catch (CryptographicException e)   
  119.         {   
  120.             //Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);   
  121.             return false;   
  122.         }   
  123.   
  124.     }   
  125.   
  126.   
  127.   
  128.     /// <summary>   
  129.     /// 将明文加密,返回 Base64 字符串   
  130.     /// </summary>   
  131.     /// <param name="Data"></param>   
  132.     /// <returns></returns>   
  133.     public string EncryptToString(string Data)   
  134.     {   
  135.         try  
  136.         {   
  137.             string base64String = string.Empty;   
  138.   
  139.             using (MemoryStream mStream = new MemoryStream())   
  140.             using (CryptoStream cStream = new CryptoStream(mStream,   
  141.                 new TripleDESCryptoServiceProvider().CreateEncryptor(byteKey, byteIV),   
  142.                 CryptoStreamMode.Write))   
  143.             {   
  144.   
  145.                 byte[] toEncrypt = new ASCIIEncoding().GetBytes(Data);   
  146.   
  147.                 cStream.Write(toEncrypt, 0, toEncrypt.Length);   
  148.                 cStream.FlushFinalBlock();   
  149.   
  150.                 byte[] ret = mStream.ToArray();   
  151.   
  152.                 base64String = Convert.ToBase64String(ret);   
  153.             }   
  154.   
  155.             return base64String;   
  156.         }   
  157.         catch (CryptographicException e)   
  158.         {   
  159.             return null;   
  160.         }   
  161.   
  162.     }   
  163.   
  164.   
  165.     /// <summary>   
  166.     /// 将密文解密,返回明文   
  167.     /// </summary>   
  168.     /// <param name="Data">密文</param>   
  169.     /// <returns>明文</returns>   
  170.     public bool Decrypt(byte[] Data, out string decrypted)   
  171.     {   
  172.         decrypted = string.Empty;   
  173.         try  
  174.         {   
  175.   
  176.             using (MemoryStream msDecrypt = new MemoryStream(Data))   
  177.             using (CryptoStream csDecrypt = new CryptoStream(msDecrypt,   
  178.                 new TripleDESCryptoServiceProvider().CreateDecryptor(byteKey, byteIV),   
  179.                 CryptoStreamMode.Read))   
  180.             {   
  181.   
  182.                 byte[] fromEncrypt = new byte[Data.Length];   
  183.   
  184.                 // Read the decrypted data out of the crypto stream   
  185.                 // and place it into the temporary buffer.   
  186.                 csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);   
  187.   
  188.                 decrypted = Encoding.UTF8.GetString(fromEncrypt);//new ASCIIEncoding().GetString(fromEncrypt);   
  189.   
  190.                 return true;   
  191.             }   
  192.         }   
  193.         catch (CryptographicException e)   
  194.         {   
  195.             return false;   
  196.         }   
  197.     }   
  198.   
  199. }  
  

 

PostService.cs

 

  1. using System;   
  2. using System.Collections.Generic;   
  3. using System.Text;   
  4.   
  5. public class PostService   
  6. {   
  7.     private System.Collections.Specialized.NameValueCollection Inputs = new System.Collections.Specialized.NameValueCollection();   
  8.     public string Url = "";   
  9.     public string Method = "post";   
  10.     public string FormName = "form1";   
  11.   
  12.     /// <summary>   
  13.     /// 添加需要提交的名和值   
  14.     /// </summary>   
  15.     /// <param name="name"></param>   
  16.     /// <param name="value"></param>   
  17.     public void Add(string name, string value)   
  18.     {   
  19.         Inputs.Add(name, value);   
  20.     }   
  21.   
  22.     /// <summary>   
  23.     /// 以输出Html方式POST   
  24.     /// </summary>   
  25.     public void Post()   
  26.     {   
  27.         System.Web.HttpContext.Current.Response.Clear();   
  28.   
  29.         string html = string.Empty;   
  30.   
  31.         html += ("<html><head>");   
  32.         html += (string.Format("</head><body onload=\"document.{0}.submit()\">", FormName));   
  33.         html += (string.Format("<form name=\"{0}\" method=\"{1}\" action=\"{2}\" >", FormName, Method, Url));   
  34.         try  
  35.         {   
  36.             for (int i = 0; i < Inputs.Keys.Count; i++)   
  37.             {   
  38.                 html += (string.Format("<input name=\"{0}\" type=\"hidden\" value=\"{1}\">", Inputs.Keys[i], Inputs[Inputs.Keys[i]]));   
  39.             }   
  40.             html += ("</form>");   
  41.             html += ("</body></html>");   
  42.   
  43.             System.Web.HttpContext.Current.Response.Write(html);   
  44.             System.Web.HttpContext.Current.Response.End();   
  45.         }   
  46.         catch (Exception ee)   
  47.         {   
  48.             //   
  49.         }   
  50.     }   
  51. }  

 

SSORequest.cs

 

  1. using System;   
  2. using System.Data;   
  3. using System.Configuration;   
  4. using System.Web;   
  5. using System.Web.Security;   
  6. using System.Web.UI;   
  7. using System.Web.UI.WebControls;   
  8. using System.Web.UI.WebControls.WebParts;   
  9. using System.Web.UI.HtmlControls;   
  10.   
  11. [Serializable]   
  12. public class SSORequest : MarshalByRefObject   
  13. {   
  14.     public string IASID;         //各独立站点标识ID   
  15.     public string TimeStamp;     //时间戳   
  16.     public string AppUrl;        //各独立站点的访问地址   
  17.     public string Authenticator; //各独立站点的 Token   
  18.   
  19.     public string UserAccount;   //账号   
  20.     public string Password;      //密码   
  21.   
  22.     public string IPAddress;     //IP地址   
  23.   
  24.     //为ssresponse对象做准备   
  25.     public string ErrorDescription = "认证失败";   //用户认证通过,认证失败,包数据格式不正确,数据校验不正确   
  26.     public int Result = -1;   
  27.   
  28.     public SSORequest()   
  29.     {   
  30.   
  31.     }   
  32.   
  33.   
  34.     /// <summary>   
  35.     /// 获取当前页面上的SSORequest对象   
  36.     /// </summary>   
  37.     /// <param name="CurrentPage"></param>   
  38.     /// <returns></returns>   
  39.     public static SSORequest GetRequest(Page CurrentPage)   
  40.     {   
  41.         SSORequest request = new SSORequest();   
  42.         request.IPAddress = CurrentPage.Request.UserHostAddress;   
  43.         request.IASID = CurrentPage.Request["IASID"].ToString();// Request本身会Decode   
  44.         request.UserAccount = CurrentPage.Request["UserAccount"].ToString();//this.Text   
  45.         request.Password = CurrentPage.Request["Password"].ToString();   
  46.         request.AppUrl = CurrentPage.Request["AppUrl"].ToString();   
  47.         request.Authenticator = CurrentPage.Request["Authenticator"].ToString();   
  48.         request.TimeStamp = CurrentPage.Request["TimeStamp"].ToString();   
  49.         return request;   
  50.     }   
  51. }  
  

 

配置web.config

 

  1. <authentication mode="Forms">   
  2.             <forms name=".AspxFormAuth" loginUrl="Default.aspx" defaultUrl="center.html" protection="All" path="/" timeout="60">   
  3.             </forms>   
  4.         </authentication>   
  5.         <authorization>   
  6.             <!--拒绝所有匿名用户-->   
  7.             <deny users="?"/>   
  8.         </authorization>  

 

最后效果如下:登录总站后,各站点之间无需再登录,可以互相访问。

 

另外,注销登录后,访问站点1 http://localhost/Site1/Default.aspx ,会自动跳转到主站登录页面 http://localhost/MasterSite/Default.aspx ,同样访问站点2 http://localhost/Site2/Default.aspx 也会转到主站登录页面。从主站登录后,分别访问站点1和站点2。

在IIS配置虚拟目录MasterSite Site1 Site2,当然你也可以新建站点MasterSite Site1 Site2,修改hosts表
127.0.0.1      http://www.mastersite.com/

127.0.0.1      http://www.site1.com/

127.0.0.1      http://www.site2.com/

源代码下载:http://download.csdn.net/source/1571879