| 今天遇到了一个问题. 公司有两个产品需要整合, 
                          需要实现一个SSO... 后台做完了, 到前台这里发现了个巨大的问题: 因为这两套系统是在两个域名, 系统A在完成验证后, 
                          用户在A系统页面关闭前, 超时范围内打开B系统都不需要再次登录. 但是, B系统凭什么认为一个新发起的请求(HttpRequest)是已经验证过身份的呢? 
                          众所周知, Cookie不能跨域. 两系统共用Cookie的方式难度较大.安全性也有问题. 头疼, 开论坛. 手贱一般的点击了 "查看网页源代码"... 
                          这个网页的源码中有一句话让我眼前一亮: <script language="javacript" 
                          src="http://ad.baidu.com/......."></script>... 对阿, 对script脚本的引用是可以跨域的啊!! 
                          恩, 好办法. 写个测试试一下. 下图为设计思路: 
 大体思路为: 首先在B系统的那个需要A系统数据的那个页面, 
                          添加一个脚本引用. 注意, 这里的脚本引用不指向一个真实的JS文件, 而是指向A系统的一个WebHandler或者ASHX. 这样在打开B系统的页面时, 就会调用A系统的那个WebHandler(或ASHX), 
                          而这个WebHandler(或ASHX)因为属于A系统, 所以可以调用A系统中当前请求的Session或者Cookie. 然后以脚本输出的方式输出成几个带有来自A系统数据的Javascript字段. 
                          然后B系统的页面就可以通过脚本访问到字段的值. 也就是说这个WebHandler(ASHX)就充当了桥梁. 至于之后是直接显示在页面上啊还是提交到服务器就是后话了.. 不明白啊? 举个例子: B公司需要A公司提供一些文本资料, 
                          可是B公司的员工无权直接去A公司拿取资料, 因为A公司的人不认识他. 那么有一个办法, 就是B公司请求A公司派一个 
                          "大使" 将资料送来. 那么这个 "大使" 既可以从A公司拿取资料, 
                          因为他本身就是A公司的人, 也可以将资料交付给B公司. 因为身在B公司的办公室. 好, 首先建立两个Web工程, 分别部署在两个域名下(不过我这儿只有localhost, 
                          就用两个端口分开). 一个是信息提供方, 一个是数据接受方. 这个是信息提供方的主页面. 因为是测试, 所以页面什么都没有. 我们在默认页中在Cookie中添加一些东西... 
                          (Session也行. 如果想要做A系统成功登陆关闭页面后超时前B系统自动登陆的话, 就用cookie) public partial class _Default 
                          : System.Web.UI.Page         { 
                                protected 
                          void Page_Load(object sender, EventArgs e)            
                          {           Random 
                          r=new Random(10000);            
                          Int32 i = r.Next();           i 
                          += (((DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day 
                                  + DateTime.Now.Hour 
                          + DateTime.Now.Minute + DateTime.Now.Second         + 
                          DateTime.Now.Millisecond) / 2) * i);            
                          //这里只是为了提高随机性..            
                          HttpCookie c= new HttpCookie("TEA", i.ToString()); 
                                  c.Expires 
                          = DateTime.Now + TimeSpan.FromMinutes(50);           //必须设置超时时间, 
                          否则还没等你开第二个浏览器窗口的时候Cookie就已经过期了!           Response.SetCookie(c); 
                                  Response.Write(i); 
                                  //测试结果应该是B系统的Default.aspx也显示这个. 
                                  } 
                                } 
                         下面这个就是用于处理从B系统页面发出的“伪JS”请求的HttpHandler了. 
                          
                          public class JSRequetHandler:IHttpHandler /*,IRequiresSessionState (HttpHandler如果要用Session的话必须继承这个)*/    {       #region IHttpHandler 成员       public bool IsReusable       {           get { return true; }       }       public void ProcessRequest(HttpContext context)       {           if (context.Request.Cookies["TEA"] == null)           {               context.Response.Write("var login_status = 0"); //可能是Session丢失或者非法请求.           }           else           {               context.Response.Write("var login_status = '" + context.Request.Cookies["TEA"].Value + "';");               //将上面存入Cookie中的 "TEA" 的值输出为 JS字段 "login_status" 的值. 这样B系统的页面脚本就能拿到值了.           }       }   
                             #endregion    }   因为我这里用的是HttpHandler, 所以配置文件中还得写点东西. 
                          如果是ASHX的话就不用写了.  <?xml version="1.0" encoding="utf-8"?>   <configuration>   <!--.....-->   <system.web>       <!--.....-->       <httpHandlers>           <add verb="*" path="A.cj" validate="false" type="Handler.JSRequetHandler, Handler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
         <!--所有访问A.cj(忽略路径)的请求都会由 "JSRequetHandler" 处理.-->           <!--.....-->       </httpHandlers>   </system.webServer>   </configuration>   调用页  <%@ Page Language="C#" AutoEventWireup="true"  %>   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">   <html xmlns="http://www.w3.org/1999/xhtml">   <head runat="server">       <title>B</title>       <script language="javascript" type="text/javascript" src="http://201.86.189.40:5678/TestWebSite01/A.cj"></script>       <script  runat="server">           public void OnButtonServerClick(Object sender, EventArgs arg)           {               String fromA = mk.Value;               //A系统的数经过千辛万苦终于抵达B系统的后台.           }       </script>   </head>   <body>     <br />     <br />     <br />     <br />     <center style="font-size:60pt; font-family:黑体;" id="t"></center>     <br />     <br />     <form id="f" runat="server" style="text-align:center;">       <input type="hidden" id="mk" runat="server" />         <button id="btn" runat="server" onserverclick="OnButtonServerClick">提交到服务器</button>     </form>     <script language="javascript" type="text/javascript">      var _t = document.getElementById("t");      if(typeof(login_status) != 'undefined')      {        //A系统由JSRequestHandler输出的脚本已经完成输出, 数据已经保存在字段里了.         _t.innerHTML = login_status;         document.getElementById("mk").value = login_status;               }      else      {         _t.innerHTML="-";          //如果未定义, 那么表明A系统并未提供数据.      }   </script>   </body>   </html>   测试结果: 先打开A系统(就是从上数第一个Default页所在的那个Web工程) 
                          启动后页面会输出一串数字, 然后启动B系统(调用页所在的Web工程), 所看到的数字是一致的. 测试成功. Ps:据说W3C已经出了CrossDomain的规范了? 
                          不过无论怎样, IE6还是不支持这个规范的... 毕竟中国还有好多人还在用IE6... |