求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
利用脚本文件引用解决跨域数据传递问题
 

发布于2011-10-11

 

今天遇到了一个问题. 公司有两个产品需要整合, 需要实现一个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...


相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程

 
分享到
 
 
     


使用decj简化Web前端开发
Web开发框架形成之旅
更有效率的使用Visual Studio
MVP+WCF+三层结构搭建框架
ASP.NET运行机制浅析【图解】
编写更好的C#代码
10个Visual Studio开发调试技巧
更多...   


.NET框架与分布式应用架构设计
.NET & WPF & WCF应用开发
UML&.Net架构设计
COM组件开发
.Net应用开发
InstallShield


日照港 .NET Framework & WCF应用开发
神华信息 .NET单元测试
北京 .Net应用软件系统架构
台达电子 .NET程序设计与开发
赛门铁克 C#与.NET架构设计
广东核电 .Net应用系统架构
更多...