分享

利用脚本文件引用解决跨域数据传递问题

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

    01.public partial class _Default : System.Web.UI.Page
    02.{
    03. protected void Page_Load(object sender, EventArgs e)
    04. {
    05. Random r=new Random(10000);
    06. Int32 i = r.Next();
    07. i += (((DateTime.Now.Year + DateTime.Now.Month + DateTime.Now.Day + DateTime.Now.Hour + DateTime.Now.Minute + DateTime.Now.Second + DateTime.Now.Millisecond) / 2) * i);
    08. //这里只是为了提高随机性..
    09.
    10. HttpCookie c= new HttpCookie("TEA", i.ToString());
    11. c.Expires = DateTime.Now + TimeSpan.FromMinutes(50);
    12. //必须设置超时时间, 否则还没等你开第二个<a class="keylink" href="http://www./edu/ewl/" target="_blank">浏览器</a>窗口的时候Cookie就已经过期了!
    13.
    14. Response.SetCookie(c);
    15.
    16.
    17. Response.Write(i);
    18. //测试结果应该是B系统的Default.aspx也显示这个.
    19. }
    20.}

    下面这个就是用于处理从B系统页面发出的“伪JS”请求的HttpHandler了.

    01.public class JSRequetHandler:IHttpHandler /*,IRequiresSessionState (HttpHandler如果要用Session的话必须继承这个)*/
    02.{
    03. #region IHttpHandler 成员
    04.
    05. public bool IsReusable
    06. {
    07. get { return true; }
    08. }
    09.
    10. public void ProcessRequest(HttpContext context)
    11. {
    12. if (context.Request.Cookies["TEA"] == null)
    13. {
    14. context.Response.Write("var login_status = 0"); //可能是Session丢失或者非法请求.
    15. }
    16. else
    17. {
    18. context.Response.Write("var login_status = '" + context.Request.Cookies["TEA"].Value + "';");
    19. //将上面存入Cookie中的 "TEA" 的值输出为 JS字段 "login_status" 的值. 这样B系统的页面脚本就能拿到值了.
    20. }
    21. }
    22.
    23. #endregion
    24.}

    因为我这里用的是HttpHandler, 所以配置文件中还得写点东西. 如果是ASHX的话就不用写了.

    01.<?xml version="1.0" encoding="utf-8"?>
    02.<configuration>
    03.<!--.....-->
    04.<system.web>
    05. <!--.....-->
    06. <httpHandlers>
    07. <add verb="*" path="A.cj" validate="false" type="Handler.JSRequetHandler, Handler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
    08. <!--所有访问A.cj(忽略路径)的请求都会由 "JSRequetHandler" 处理.-->
    09. <!--.....-->
    10. </httpHandlers>
    11.</system.webServer>
    12.</configuration>

    调用页

    01.<%@ Page Language="C#" AutoEventWireup="true" %>
    02.
    03.<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd">
    04.
    05.<html xmlns="http://www./1999/xhtml">
    06.<head runat="server">
    07. <title>B</title>
    08. <script language="javascript" type="text/javascript" src="http://201.86.189.40:5678/TestWebSite01/A.cj"></script>
    09. <script runat="server">
    10. public void OnButtonServerClick(Object sender, EventArgs arg)
    11. {
    12. String fromA = mk.Value;
    13. //A系统的数经过千辛万苦终于抵达B系统的后台.
    14. }
    15. </script>
    16.</head>
    17.<body>
    18. <br />
    19. <br />
    20. <br />
    21. <br />
    22. <center style="font-size:60pt; font-family:黑体;" id="t"></center>
    23. <br />
    24. <br />
    25.
    26. <form id="f" runat="server" style="text-align:center;">
    27. <input type="hidden" id="mk" runat="server" />
    28. <button id="btn" runat="server" onserverclick="OnButtonServerClick">提交到服务器</button>
    29. </form>
    30.
    31. <script language="javascript" type="text/javascript">
    32.
    33. var _t = document.getElementById("t");
    34.
    35. if(typeof(login_status) != 'undefined')
    36. {
    37. //A系统由JSRequestHandler输出的脚本已经完成输出, 数据已经保存在字段里了.
    38. _t.innerHTML = login_status;
    39. document.getElementById("mk").value = login_status;
    40.
    41. }
    42. else
    43. {
    44. _t.innerHTML="-";
    45. //如果未定义, 那么表明A系统并未提供数据.
    46. }
    47.</script>
    48.
    49.</body>
    50.</html>

    测试结果: 先打开A系统(就是从上数第一个Default页所在的那个Web工程) 启动后页面会输出一串数字, 然后启动B系统(调用页所在的Web工程), 所看到的数字是一致的. 测试成功.

    Ps:据说W3C已经出了CrossDomain的规范了? 不过无论怎样, IE6还是不支持这个规范的... 毕竟中国还有好多人还在用IE6...

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多