Web应用跨域访问解决方案

2019年12月06日 阅读数:81
这篇文章主要向大家介绍Web应用跨域访问解决方案,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

转自:http://blog.csdn.net/carechere/article/details/51836877javascript

作过跨越多个网站的Ajax开发的朋友都知道,若是在A网站中,咱们但愿使用Ajax来得到B网站中的特定内容,若是A网站与B网站不在同一个域中,那么就出现了跨域访问问题。Ajax的跨域访问问题是现有的Ajax开发人员比较常遇到的问题。
IE对于跨域访问的处理是,弹出警告框,提醒用户。若是用户将该网站归入可信任网站,或者调低安全级别,那么这个问题IE就不会在提醒你。
FireFox等其它非微软的浏览器遇到跨域访问,则解决方案统一是拒绝访问。
有人说,IE是主流浏览器,只要它能正常使用就行了。此言差已,IE虽然可以处理,可是是有前提的,要么用户不厌其烦地在页面弹出警告框以后点击是(点击否就不执行该Ajax调用了),要么用户将该网站归入可信任站点。这两种作法,在企业管理系统的应用中却是比较常见,由于系统管理员能够以行政手段保证用户的行为。可是对于互联网上的网站或者门户开发,这种作法则不行。
php

最近遇到了这个问题,须要在跨域访问结束以后完成使主窗口出现一些特效,搜索了一些资料,经过不断尝试以及在不一样浏览器中进行兼容性测试,找到了几个可行的Web应用跨域访问解决方案:
一、Web代理的方式。html

即用户访问A网站时所产生的对B网站的跨域访问请求均提交到A网站的指定页面(Post页面过去),由该页面代替用户页面完成交互,从而返回合适的结果。此方案能够解决现阶段所可以想到的多数跨域访问问题,但要求A网站提供Web代理的支持,所以A网站与B网站之间必须是紧密协做的,且每次交互过程,A网站的服务器负担增长,且没法代用户保存session状态。html5


二、on-Demand方式。java

MYMSN的门户就用的这种方式,不过MYMSN中不涉及跨域访问问题。动态控制script标记的生成,经过修改script标记的src属性完成对跨域页面的调用。此方案存在的缺陷是,script的src属性完成该调用时采起的方式时get方式,若是请求时传递的字符串过大时,可能会没法正常运行。不过此方案很是适合聚合类门户使用。node


三、iframe方式。mysql

查看过醒来在javaeye上的一篇关于跨域访问的帖子,他提到本身已经用iframe的方式解决了跨域访问问题。数据提交跟获取,采用iframe这种方式的确能够了,但因为父窗口与子窗口之间不能交互(跨域访问的状况下,这种交互被拒绝),所以没法完成对父窗口效果的影响。android

四、用户本地转储方式。web

IE自己依附于windows平台的特性为咱们提供了一种基于iframe,利用内存来“绕行”的方案,即两个window之间能够在客户端经过windows剪贴板的方式进行数据传输,只须要在接受数据的一方设置Interval进行轮询,得到结果后清除Interval便可。FF的平台独立性决定了它不支持剪贴板这种方式,而以往版本的FF中存在的插件漏洞又被fixed了,因此FF没法经过内存来完成暗渡陈仓。而因为文件操做FF也没有提供支持(没法经过Cookie跨域完成数据传递),导致这种技巧性的方式只能在IE中使用。ajax


五、我本身用于解决这类问题的方式.

结合了前面几种方式,在访问A网站时,先请求B网站完成数据处理,再根据返回的标识来得到所需的结果。这种方法的缺点也很明显,B网站的负载增大了。优势,对session也实现了保持,同时A网站与B网站页面间的交互能力加强了。最重要的一点,这种方案知足了个人所有须要。
总结一下,以上方案中可选择的状况下,我最推荐on-Demand方式,在不须要提交大量数据的状况下,这种方式可以解决您的大部分问题。


==========================================================


跨平台跨服务器跨网站SSO(单点登陆)的方案

最近在研究SSO,看到各类复杂的解决方案以为很疑惑,本身想出了个简单有效的方案,你们来评评有什么问题吗?
服务器A:网站A
服务器B:网站B
服务器C:验证网站(验证表中有UID和KEY两个字段)。

1.       用户打开网站A的页面http://服务器A/a.aspx,检测发现网站Session中没有存储用户名UID。

2.       系统转到验证服务器登陆页面,并在QUERYSTRING中附加前一个页面的URL地址。好比http://服务器C/login.asp?URL=http://服务器A/a.aspx

3.       在验证服务器登陆成功后更新验证服务器的Session(超时设置为足够长,好比1天)。而后生成一个GUID值,写入验证表。最后,把这个GUID值和UID保存到一个类中序列化后附加在URL中返回网站A的那个页面。

好比http://服务器A/a.aspx? token=sadhsagdkjasgyugd7d8yweihasdiuhagsdiuashdhaiushdi

4.       网站A的页面读取QUERYSTRING,而后反序列化出一个类,读取类的UID和KEY信息。而后,从数据库中查找匹配的记录,若是找到了则代表登陆成功,并把这条记录的KEY更新成另一个GUID(这样就保证了即便这个URL被别人拿走再登陆都不能成功)。把UID写入服务器A的Session中便可。

5.       用户打开网站B的页面http://服务器B/b.aspx,服务器B上没有当前用户的Session信息,自动转向验证服务器检测是否存在Session,若是找到了代表用户已经登陆过,再重复步骤3和4,若是没有找到就转到验证服务器的登陆页面。
巧妙之处在于:

l         网站服务器和验证服务器都拥有一份和用户关联的Session,验证到时候不须要传任何和UID相关的信息,所以也能够跨服务器。正由于如此不须要使用cookie也解决了跨域名。

l         网站服务器和验证服务器可使用本身的状态机制(不必定是Session),所以跨平台也没有问题。

l         用于验证用户的TOKEN使用GUID在每次验证的时候都会更换,并且GUID和UID是捆绑在一块儿的,即便GUID碰巧对上了也不知道这个GUID对应了哪一个UID。

l         经过验证服务器的验证后,服务器发回的token数据通过了序列化,用户很难伪造。
(实在不放心还能够对这个token进行加密)
不知道你们是否理解了?
更新:通过网友提醒,我想到这个方案在登出的时候有严重问题,好比A网站登出了,咱们不能通知其它网站该用户已经登出,它再切换到其它网站又是登陆状态(由于Session没有过时),不过我也想到了一个解决方案。就是全部的网站都有一个专门的页面或者服务,根据传过来的令牌来清空这个当前用户的Session。登出之后把全部网站的Session都清空,若是网站不是不少的状况下还好,网站一多登出就会很慢了!
更新:如今看来已经没有什么问题了,到时候放出完整DEMO!
更新:有网友不理解为何关闭浏览器全部网站退出登陆?由于Session是和用户浏览器实例关联的,而咱们全部网站都使用Session,所以关闭了浏览器全部网站都退出了。这个和退出登陆按钮不同,退出登陆按钮须要发通知让全部网站清除Session。
更新:咱们如今把这个框架的登陆放到了各个网站中,保证登陆和退出在登陆服务器Down的状况下也能进行,只是不能进行跨站登陆罢了。登陆服务器Down还能实现本站登陆和退出。过几天放出完整源代码!


==========================================================


单点登录问题-实现单点登录的几种方法
1 能够实现单点登录的几种方法

(1)基于domain的方案
这种方案是我公司目前使用的一种方案,原理:应用A在a.domain.com,B在b.domain.com,若是设cookie的时候,设domain为domain.com,那在A、B上均可以访问到这个cookie了。(cookie的domain、path、port、version、secure相同)。
该方案特色:
一、不可以跨域
二、在网络中传送用户名和密码
三、只支持J2EE应用
(2)基于gateway的方案
实际部署的时候,对全部应用的请求,都要经过一个gateway转发一下,好比用一个L4的交换机顶在前面。
(3)基于tooken传递的方案
主要是以耶鲁大学的CAS项目为基础。
注意:你本身的应用看不到用户的密码。由CAS执行受权,只有CAS能看到用户的密码。这样增长发安全性,由于用户名和密码不会经过网络在应用间传播。
下面是使用CAS整合的单点登陆用例
用例一:
一台认证服务器(假定为AUTH),有两个应用A、B,分别部署在不一样的服务器上。
1) 用户访问A,A应用没法找到用户的身份信息,使用redirect方法将用户引导至http://Auth/login?service=http://A/path。
2) AUTH 显示登陆界面,用户输入登陆信息,认证经过。
3) AUTH产生一个cookie(这个cookie只有AUTH上才能读到),使用redirect方法将用户引导回http://A/path?token=xxxxx(在有的解决方案上,这个token是经过必定编码算法的Account信息)
4) A读取token=xxxx的信息,获取用户身份。
5) 用户访问B。B未找到用户的身份信息,redirect至http://AUTH/login?service=http://B/path
6) AUTH读cookie获取用户身份,而后redirect回http://B/path?token=xxxx
7) B读取token=xxxx信息,得到用户身份信息
用例二:
用户访问一个Web应用的过程。

具体的参看 http://www.9ta8.com/YaleCASServer.mht
(4)USBKey登陆
这个方案是北京点聚信息技术有限公司提供的,我也向他们的技术咨询了相关的问题。他们的实现方式基本上是这样的:每一个使用该系统的用户都有一个USBKey证书,在登录系统的时候把这个证书插在计算机上。每个网站都要经过这个证书去认证。
这样每一个登陆用户只需插上USBKey便可进入任意受信任系统,固然访问USBKey首先须要密码校验。
2  我的认为单点登录实际上就两种方案
首先确认要使用单点登录,必须有一个核心,那就是无论用户走到那个平台,他必需要带着他的通行证,单点登录最关键的问题是用户怎么取得、保存、使用这个通行证的问题。  用户要取得他的通行证其实不外乎如下两种方案:
第一种:全部的业务平台集成在一个Portal上,去每个平台的时候都要带着他的“通行证”,这就是所谓的“Tooken传递方案”;
第二种:使用硬件卡,就是上面所说的“USBKey登录”;
3  单点登录的几个案例
(1)微软一篇关于单点登录的文章,他的实现是使用第一种方案。
原文:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/singlesignon.asp

(2)SharePoint Portal Server 2003 中的单一登陆

http://www.microsoft.com/china/technet/prodtechnol/sppt/reskit/c2661881x.mspx

(3)《WebCast SharePoint Portal Server 2003 Single Sign On 管理及开发》已提供下载

http://www.msotec.NET/Forums/ShowThread.aspx?PostID=415

4  单点登录的参考方法
服务器端可控JS跨域访问解决方法

http://bbs.ad0.cn/viewthread.PHP?tid=302&extra=page%3D1

SSO – Single Sign-On Enterprise Security for Web Applications

http://bbs.ad0.cn/viewthread.php?tid=304&extra=page%3D1

单点登陆的简单实现

http://bbs.ad0.cn/viewthread.php?tid=305&extra=page%3D1

PHP实现WebServices和跨域自动登录

http://bbs.ad0.cn/viewthread.php?tid=307&extra=page%3D1

Passport跨域认证解决方法

http://bbs.ad0.cn/viewthread.php?tid=309&extra=page%3D1

Web应用跨域访问解决方案

http://bbs.ad0.cn/viewthread.php?tid=310&extra=page%3D1

Flex或Flash的跨域访问解决方案

http://bbs.ad0.cn/viewthread.php?tid=313&extra=page%3D1

跨域访问新方案-PHPRPC

http://bbs.ad0.cn/viewthread.php?tid=315&extra=page%3D1

==========================================================
PHP使用P3P完成跨域COOKIE操做[转载]
实际工做中,相似这样的要求不少,好比说,咱们有两个域名,咱们想实如今一个域名登陆后,能自动完成另外一个域名的登陆,也就是PASSPORT的功能。
为了测试的方便,先编辑hosts文件,加入测试域名(C:\WINDOWS\system32\drivers\etc\hosts)
127.0.0.1       www.a.com
127.0.0.1       www.b.com
首先:建立 a_setcookie.php 文件,内容以下:
<?php
//header(‘P3P: CP=”CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR”‘);
setcookie(“test”, $_GET['id'], time()+3600, “/”, “.a.com”);
?>
而后:建立 a_getcookie.php 文件,内容以下:
<?php
var_dump($_COOKIE);
?>
最后:建立 b_setcookie.php 文件,内容以下:
<script src=”http://www.a.com/a_setcookie.php?id=www.b.com”></script>
----------------------------
三个文件建立完毕后,咱们经过浏览器依次访问:

http://www.b.com/b_setcookie.php

http://www.a.com/a_getcookie.php

咱们会发现,在访问b.com域的时候,咱们并无在a.com域设置上cookie值。
而后咱们修改一下a_setcookie.php文件,去掉注释符号,a_setcookie.php即为:
<?php
header(‘P3P: CP=”CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR”‘);
setcookie(“test”, $_GET['id'], time()+3600, “/”, “.a.com”);
?>
再次经过浏览器依次访问:

http://www.b.com/b_setcookie.php

http://www.a.com/a_getcookie.php

此次,你会发如今访问b.com域的时候,咱们设置了a.com域的cookie值。

==========================================================
跨域(cross-domain)访问 cookie (读取和设置)[转,保存][转载]

Passport 一方面意味着用一个账号能够在不一样服务里登陆,另外一方面就是在一个服务里面登陆后能够无障碍的漫游到其余服务里面去。坦白说,目前 sohu passport 在这一点实现的很烂(不过俺的工做就是要把它作好啦,hehe)
搜狐的 SSO 需求比较麻烦,由于它旗下有好多域名:sohu.com、chinaren.com、sogou.com、focus.cn、17173.com、go2map.com,登陆用户漫游的主要障碍也来自于此。
之前亿邮的邮件系统在和别的系统整合的时候是提供一个 URL,用户从第三方系统里面点击这个连接就能够生成访问邮件界面所需的 cookie,而后进入邮件。这个方式的确颇有效,但问题是:
1. 每一个外部连接都必须用特殊的 URL 跳转,维护很麻烦
2. 两个系统集成已经很麻烦了,如果集成的系统有好几个,彼此都须要跳转而缺少一个中心机制就成了噩梦
3. 根本没法处理用户直接在地址栏输入地址进行访问的状况
即便是跨域,上述的解决方法相对来讲仍是容易的。
A. 首先是全部登陆必须首先经过一个中央服务器进行认证,而后在它那里给浏览器种下 cookie(下面称之为 sso cookie)
B. 当用户访问另外的域名 app 的时候,浏览器是没法直接发送 sso cookie 给服务器认证的。此时应该利用 ,动态建立一个隐藏的 ,让其访问 sso
C. 这个 i 的请求是能够把 sso cookie 送给 sso server 的。sso server 验证 cookie 后,返回一个重定向页面到 app 的某个 URL,由该 URL 设置 app cookie
D. 此时浏览器上可看见的页面容器实际上也是能够和重定向回来的内容交互的。好比能够用 js 控制发现重定向页面成功返回后,就刷新整个页面,让它看起来和用户登陆后访问没有什么区别。
下面是真正的技巧:怎样才能在 IE 里面跨域去设置 cookie
上述技术看起来是否是很好?但它的前提是全部的登陆都 post 到 sso server 上,认证成功后再返回 app 页面。可我接受到的需求之一就是要支持页面无刷新登陆。
哈!就是说原本在 chinaren.com 上提交登陆表单的 action 应该是 passport.sohu.com 这个 sso server。但是在 AJAX 大潮下,chinaren 计划采用 HTTPRequest 提交,这个就麻烦了,由于是不能跨域来提交的。
那么解决方法就是跨域产生 cookie,即 js 发现口令校验成功后,再在 passport.sohu.com 上种上合法的 cookie.
套用上面的跨域读 cookie 的方案彷佛很简单去推论:就是建立一个隐含的 iframe,让那个 iframe 去调用 passport.sohu.com 的 URL 来产生 cookie。很遗憾,此方法在 Fx 下工做的很好,可是不能在 IE 上应用。(在 IE 状态栏上显示 cookie 隐私警告,红色圆底白横杠)
我试了不少不少方法,包括建立 、 node,包括用 js 设置,但都一次次被 IE 无情的挡在了浏览器外。google 之,也没有任何真正可用的答案,中文网页要么介绍的方法是错的,要么说无解。
最后仍是在 chinaren 一哥们的帮助下,翻出了他们所使用的,以和 alumni.sohu.com 交互的方法(不知道是哪位牛人发现的),只须要设置 P3P HTTP Header,在隐含 iframe 里面跨域设置 cookie 就能够成功。他们所用的内容是:
P3P: CP=’CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR’
最后是我作的一个小小的演示:cookie 怎么在 vmx.cn 和 dup2.Net 之间交互
1. http://qiuyingbo.test.vmx.cn/cookie.php
2. 随便输入什么,点 reset cookie,就能够看到 vmx.cn 的 cookie 已经被设上了
3. 在该页面点链接到 http://www.dup2.net/vmx/cookie.html
4. 点’get corss-domain cookie’ .. (此时 js 会去建立一个iframe,请求 qiuyingbo.test.vmx.cn ,返回页面把 cookie 值做为 GET 参数重定向回 dup2.net 的另一个URL。)
5. 点 ‘display corss-domain cookie’ .. 就能够看到 vmx.cn 的 cookie 了
6. 在该页面的输入框中输入其它的值,而后点 ’set cross-domain cookie’,该行为将主动设置 vmx.cn 的 cookie
7. 点连接回到 http://qiuyingbo.test.vmx.cn/cookie.php ,就能够看到新的值了
经过设置P3P头来实现跨域访问COOKIE

==========================================================

单点登陆的简单实现
SSO 单点登陆的简单实现 实现门户网站单点登陆
在门户项目中,常常会遇到如何实现单点登陆的问题,下面就本人的经验作个总结。欢迎你们进行补充讨论。
单点登陆的具体实现有不少种选择,包括:
采用专门的SSO商业软件: 主要有:Netgrity的Siteminder,已经被CA收购。Novell 公司的iChain。RSA公司的ClearTrust等。
采用门户产品供应商本身的SSO产品,如:BEA的WLES,IBM 的Tivoli Access Manager,Sun 公司的identity Server,Oracle公司的OID等。
这些商业软件通常适用于客户对SSO的需求很高,而且企业内部采用COTS软件如:Domino,SAP,Sieble的系统比较多的状况下采用。并结合身份管理。统一认证等项目采用。采用这些软件通常都要对要集成的系统作些改造,如在要集成的系统上安装AGENT。如今通常只提供常见软件如:Domino,SAP,Sieble,常见应用服务器:weblogic,websphere等的AGENT。要先统一这些系统的认证。通常采用LDAP或数据库。而后才能实现SSO。比较麻烦。
另外,若是不想掏银子,也有OPEN SOURCE的SSO软件可选:主要有:http://www.josso.org/ https://opensso.dev.Java.net/ http://www.sourceid.org 等。具体怎么样就不清楚了。

==========================================================

在PHP中实现单点登陆(Single Sign On)的一种简单方法
单点登陆是大容量系统必备的功能,市面上有几款昂贵的商业系统,若不是财大气粗,恐怕用不起。
怎么样才能简单、经济的实现这个功能?咱们在这里探讨一种可行的方案。
当前开发Web应用中,Apache + PHP + MySQL是中小型企业下降成本的必选架构,这里咱们来实现PHP的单点登陆,让这种经济性的架构可以扩展到的群集服务器层面。
咱们的设想是将PHP的Session数据集中存储,这样对于不一样服务器中运行的PHP来讲,只有一个共有的Session数据库,那么用户在服务器A登陆所生成的Session数据在服务器B、C、D等服务器均可以共享,就能够免除屡次登陆。但因为PHP的Session是须要Cookie的,而Cookie又是与域名相关的,因此采用这个方案的各个服务器须要有相同的域名(至少是相同的二级域名),好比:
一、全部服务器的域名都是www.whybsd.com,这个东东DNS轮询就能够实现;这个时候,在PHP中将Cookie域名设置为www.whybsd.com便可;
二、全部服务器的域名都是以.whybsd.com结尾的三级域名,好比a.whybsd.com,b.whybsd.com等等,这个时候,在PHP中将Cookie域名设置为.whybsd.com就能够共享Cookie了。
解决了先决条件,咱们如今来看看PHP的Session存储方法,在PHP手册说明中,有一个叫session_set_save_handler()的函数,这个函数是用来注册用户自定义的Session数据存储接口的。
如下是PHP手册自带的示例:
代码:

<?php
function open($save_path, $session_name) {
global $sess_save_path, $sess_session_name;

$sess_save_path = $save_path;
$sess_session_name = $session_name;
return(true);
}
function close() {
return(true);
}
function read($id) {
global $sess_save_path, $sess_session_name;
$sess_file = “$sess_save_path/sess_$id”;
if ($fp = @fopen($sess_file, “r”)) {
$sess_data = fread($fp, filesize($sess_file));
return($sess_data);
} else {
return(“”); // Must return “” here.
}
}
function write($id, $sess_data) {
global $sess_save_path, $sess_session_name;
$sess_file = “$sess_save_path/sess_$id”;
if ($fp = @fopen($sess_file, “w”)) {
return(fwrite($fp, $sess_data));
} else {
return(false);
}
}
function destroy($id) {
global $sess_save_path, $sess_session_name;

$sess_file = “$sess_save_path/sess_$id”;
return(@unlink($sess_file));
}
/*********************************************
* WARNING – You will need to implement some *
* sort of garbage collection routine here.  *
*********************************************/
function gc($maxlifetime) {
return true;
}
session_set_save_handler(“open”, “close”, “read”, “write”, “destroy”, “gc”);
session_start();
// proceed to use sessions normally
?>

按照这种思路,咱们只要编写本身的处理函数并进行相应的注册,就能够实现PHP Session数据的自定义存储了。
具体实现能够开动你的思路,好比可使用NFS将Session数据存储到统一的网络设备中,也能够将Session数据保存到一个数据库中,让全部服务器链接这个共享数据库(好比MySQL)就能够了。
嗯,比较简单,并且经济。
更多考虑:
一、性能须要考量,特别是服务器数(引发资源占用)和用户量(引发Session量)很是巨大的时候。
==========================================================
PHP实现WebServices和跨域自动登录
一、webservices的php实现
主要是基于nusoap这个库来实现的,其不但能够实现server功能还能够实现client功能,支持end point和WSDL两种方式;连soap协议的xml消息都是本身解析的,因此彻底能够脱离其余php库支持;优势之一啊;惋惜,可能有性能上的忧虑。
二、session跨域自动登录
了解http协议特性的人都知道(参考RFC),服务端session只能是经过cookie或者get、post方法传递的unique id来实现的;所以欺骗服务端session的行为理论上是很容易实现的,只要你知道那个unique id及传递的方式;而在某个session建立以后,只要传递给其该惟一标示,其都是能够被承认为会话客户的;所以,在得到会话id的前提下任何跨域session访问都是可能的。经过get、post方式的id容易拿到和建立,而经过cookie传递的就必须突破浏览器的跨域cookie建立限制,固然若是须要实现跨域session建立的是可控制的服务端,那问题就迎刃而解了(不过该条件下的解决方案有多种,例如互连星空就使用的URL转向方法)。PHP实现WebServices和跨域自动登录具体例子就不详述了。
==========================================================
Passport跨域认证解决方法
很是简单的Passport跨域认证解决方法:
一、架设一个PASSPORT服务器(该服务器命名为A)。全部的用户验证都经过此服务器验证,其余服务器对用户信息的获取,用户的身份确认,都要经过这个服务器来实现。
二、在应用服务器(该服务器命名为B)的全部须要验证的地方判断用户信息是否已经验证,若是没有验证,则经过 IFRAME 在用页面放一个A服务器的验证页面,并传递一个A能够识别的标记参数,告诉A服务器是B服务器须要验证当前用户。
三、A服务器得到B服务器的页面请求后,首先检查当前用户是否登录,若是没有登录,则中止验证,或者反馈一个还没有登录的页面。
四、若是A用户收到B服务器的也面请求后,发现当前用户已经登录,则生成一个随机的长的字符串并在记录下该字符串、生成时间、对应的用户记录、B服务器的标记。而后经过自动跳转技术,访问B服务器上的一个用户信息验证页面,同时传递所生成的长字符串。(该页面由A从自身记录中获取,由事先录入);
五、B服务器的验证页面收到到所传递的长字符串后,在服务器端访问A服务器的服务器端信息确认页面,同时传递所收到的长字符串以及服务器标识。
六、A服务器的服务器端信息确认页面收到信息后,经过字符串与发出请求的服务器来验证信息的正确性:
(1)首先判断服务器IP是否属于该PASSPORT的服务服务器列表;
(2)经过字符串查询记录中是否有该字符串;
(3)经过请求服务器的IP与保留的服务器标记核对,看是否请求的IP地址是当前记录的服务器的;
(4)判断字符串的生成时间与当前时间比较,是否超时,超时的设置,在A服务器上设置;
(5)若是都核对无误,则返回对应的用户信息,不然反馈错误信息;
七、B服务器受到A服务器的确认信息后,根据确认信息的内容,判断用户是否登录成功,若是登录成功,则给当前用户分配SESSION。若是不成功,则返回空白或者重复刚才的进程,从新验证(从新验证须要记录次数,当次数超过必定量,则无条件中止验证,避免死循环)

Passport跨域认证解决方法 参考:
服务器端可控JS跨域访问解决方法

http://bbs.ad0.cn/viewthread.php?tid=302&extra=page%3D1

SSO – Single Sign-On Enterprise Security for Web Applications

http://bbs.ad0.cn/viewthread.php?tid=304&extra=page%3D1

单点登陆的简单实现

http://bbs.ad0.cn/viewthread.php?tid=305&extra=page%3D1

PHP实现WebServices和跨域自动登录

http://bbs.ad0.cn/viewthread.php?tid=307&extra=page%3D1

Passport跨域认证解决方法

http://bbs.ad0.cn/viewthread.php?tid=309&extra=page%3D1

Web应用跨域访问解决方案

http://bbs.ad0.cn/viewthread.php?tid=310&extra=page%3D1

Flex或Flash的跨域访问解决方案

http://bbs.ad0.cn/viewthread.php?tid=313&extra=page%3D1

跨域访问新方案-PHPRPC

http://bbs.ad0.cn/viewthread.php?tid=315&extra=page%3D1

SSO-单点登陆彻底解决方案
—-最全的SSO解决方案,
AJAX跨域问题,IFrame跨域问题,Cookies跨域,session跨域问题,Js跨域问题,等常见跨域问题均有说起
Ajax跨域工具: Modello.ajax
—跨浏览器、跨域的Ajax工具

跨域访问新解决方案(跨域调用新方案)- PHPRPC
PHPRPC – perfect high performance remote procedure call
PHPRPC 是一个轻型的、安全的、跨网际的、跨语言的、跨平台的、跨环境的、跨域的、支持复杂对象传输的、支持引用参数传递的、支持内容输出重定向的、支持分级错误处理的、支持会话的、面向服务的高性能远程过程调用协议。
目前该协议的最新版本为 3.0。该版本目前已有如下几种语言的实现:

ASP:提供 JScript 和 VBScript 两种语言的支持。
ActionScript:提供 ActionScript 2.0 和 ActionScript 3.0 两个版本的支持。
Java:支持 JDK 1.4 以上的全部版本,它还支持 Google Android 开发包。
JavaScript:提供两个版本的实现,一个使用纯 JavaScript 实现,另外一个须要调用一个 swf 文件,两个版本都支持跨域的远程过程调用,可是使用 swf 的版本不限制参数长度,而且有更好的安全控制机制。这两个版本已经经过完整测试的浏览器包括 IE 5+,Netscape 7+,Firefox,Mozilla,Opera,Safari,Epiphany,Camino 与 Konqueror。而且纯 JavaScript 版本还经过了 Pocket IE、Opera Mini、Opera Mobile、iPhone、Android 等手持设备浏览器的测试。
.NET:支持 .NET 框架下全部的语言(如 C#、VB.NET、VC.NET、Delphi.NET 等),而且支持目前全部版本的 .NET Framework 和 .NET Compact Framework,固然它也支持 Mono。
PHP:支持 PHP4 与 PHP5,一样支持正处于开发阶段的 PHP6。
Perl:目前该版本尚不成熟,有待完善。
其中 ASP、.NET、Java 和 PHP 版本除了提供客户端实现外,还提供了 服务器端实现。

PHPRPC 3.0下载:http://www.phprpc.org/download/phprpc_3.0.zip

PHPRPC 3.0各版本: http://www.phprpc.org/zh_CN/download/
搜索《跨域访问新方案-PHPRPC》相关主题: 远程调用 跨域调用 解决方案 跨域访问 PHPRPC PHPRPC 方案 访问

==========================================================
php sso单点登陆实现方案

http://www.dayanmei.com/blog.php/ID_1021.htm

因为已经现成有多个不一样的应用,各个应用有本身的user数据,我拟定的作法是
1.    共建一个user表,经过应用绑定用户跟user表的关系
拷贝全部现有的用户和密码到新表,并验证密码的验证方式函数
2.    一个配置文件中设置各个应用与user表之间传输加密解密协议
3.    当一个用户登陆时他首先携带当前的url地址或者是须要返回的url地址和经过加密协议加密后的字串提交到验证服务器,验证后返回加密后的状态和票据,其中可能包含过时时间产生时间等,
若是成功,则一样的票据经过javascript src的方式提交给其余的应用,产生cookie或者session
4.    php sso单点登陆实现方案文件示例
config.inc.php 公用密钥和验证函数库
ps-mm.cn域名下文件
a_setcookie.php (产生cookie 登陆当前应用)
printcookie.php (测试打印cookie)
dayanmei.com 域名下文件
验证服务器文件
b_setcookie.php
内容:
config.inc.php
<?php
$key = ‘123456789′;
function authcode($string, $operation, $key = ”) {
$key = md5($key ? $key : $GLOBALS['auth_key']);
$key_length = strlen($key);
$string = $operation == ‘DECODE’ ? base64_decode($string) : substr(md5($string.$key), 0, 8).$string;
$string_length = strlen($string);
$rndkey = $box = array();
$result = ”;
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($key[$i % $key_length]);
$box[$i] = $i;
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if($operation == ‘DECODE’) {
if(substr($result, 0, 8) == substr(md5(substr($result, 8).$key), 0, 8)) {
return substr($result, 8);
} else {
return ”;
}
} else {
return str_replace(‘=’, ”, base64_encode($result));
}
}
//posts transaction data using libCurl
function libCurlPost($url,$data)  {
//build post string
foreach($data as $i=>$v) {
$postdata.= $i . “=” . urlencode($v) . “&”;
}
$postdata.=”cmd=_notify-validate”;
$ch=curl_init();
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$postdata);
//Start ob to prevent curl_exec from displaying stuff.
ob_start();
curl_exec($ch);
//Get contents of output buffer
//$info=ob_get_contents();
curl_close($ch);
//End ob and erase contents.
ob_end_clean();
//return $info;
}
//posts transaction data using fsockopen.
function fsockPost($url,$data) {
//Parse url
$web=parse_url($url);
//build post string
foreach($data as $i=>$v) {
$postdata.= $i . “=” . urlencode($v) . “&”;
}
$postdata.=”cmd=_notify-validate”;
//Set the port number
if($web[scheme] == “https”) { $web[port]=”443″;  $ssl=”ssl://”; } else { $web[port]=”80″; }
//Create paypal connection
$fp=@fsockopen($ssl . $web[host],$web[port],$errnum,$errstr,30);
//Error checking
if(!$fp) {
//echo “$errnum: $errstr”;
}else {
fputs($fp, “POST $web[path] HTTP/1.1\r\n”);
fputs($fp, “Host: $web[host]\r\n”);
fputs($fp, “Content-type: application/x-www-form-urlencoded\r\n”);
fputs($fp, “Content-length: “.strlen($postdata).”\r\n”);
fputs($fp, “Connection: close\r\n\r\n”);
fputs($fp, $postdata . “\r\n\r\n”);
//loop through the response from the server
while(!feof($fp)) {
$info[]=@fgets($fp, 1024);
}
//close fp – we are done with it
fclose($fp);
//break up results into a string
$info=implode(“,”,$info);
}
return $info;
}
?>
Pirntcookie.php
<?php
print $_COOKIE['test'];
?>
A_setcookie.php
<?php
header(‘P3P: CP=”CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV”‘);
include(‘config.inc.php’);
$string = explode(“\n”,authcode($_GET['string'],’DECODE’,$key));
setcookie(“test”, $string[1], time()+3600, “/”, “.ps-mm.cn”);
?>
B_setcookie.php

<script src=”http://www.ps-mm.cn/a_setcookie.php?string=f20Bq5QGXqSRKlpwuTfB”></script>


因为同源策略的限制,JavaScript跨域的问题,一直是一个比较棘手的问题,为了解决页面之间的跨域通讯,你们煞费苦心,研究了各类跨域方案。以前也有小网同窗分享过一篇“跨域,再也不纠结” 开始照着尝试时仍是有些不够明白的地方,深刻了解以后,这里给你们补充一点更具体的作法。

先来看看哪些状况下才存在跨域的问题:

编号 URL 说明 是否容许通讯

1

http://www.a.com/a.js
http://www.a.com/b.js

同一域名下

容许

2

http://www.a.com/lab/a.js
http://www.a.com/script/b.js

同一域名下不一样文件夹

容许

3

http://www.a.com:8000/a.js
http://www.a.com/b.js

同一域名,不一样端口

不容许

4

http://www.a.com/a.js
https://www.a.com/b.js

同一域名,不一样协议

不容许

5

http://www.a.com/a.js
http://70.32.92.74/b.js

域名和域名对应ip

不容许

6

http://www.a.com/a.js
http://script.a.com/b.js

主域相同,子域不一样

不容许

7

http://www.a.com/a.js
http://a.com/b.js

同一域名,不一样二级域名(同上)

不容许(cookie这种状况下也不容许访问)

8

http://www.a.com/a.js
http://www.b.com/b.js

不一样域名

不容许

其中编号六、7两种状况同属于主域名相同的状况,能够设置domain来解决问题,今天就不讨论这种状况了。 对于其余跨域通讯的问题,我想又能够分红两类,其一(第一种状况)是a.com下面的a.js试图请求b.com下某个接口时产生的跨域问题。其二(第二种状况)是当a.com与b.com下面的页面成父子页面关系时试图互相通讯时产生的跨域问题,典型的应用场景如a.com/a.html使用iframe内嵌了b.com/b.html,你们都知道a.html内的js脚本试图访问b.html时是会被拒绝的,反之亦然。 第一种状况,目前主流的方案是JSONP,高版本浏览器支持HTML5的话,还可使用XHR2支持跨域通讯的新特性。 第二种状况,目前主要是经过代理页面或者使用postMessageAPI来作,这也是今天要讨论的话题。 第二种状况,有这样一些相似的案例:a.com/a.html使用iframe内嵌了b.com/b.html,如今但愿iframe的高度能自动适应 b.html的高度,使iframe不要出现滚动条。咱们都知道跨域了,a.html是没办法直接读取到b.html的高度的,b.html也没办法把自 己的高度告诉a.html。 直接说能够用代理页面的方法搞定这个问题吧,可是怎么代理法,先来看下面这张图:

跨域

图1

b.html与a.html是不能直接通讯的。咱们能够在b.html下面再iframe内嵌一个proxy.html页面,由于这个页面是放在 a.com下面的,与a.html同域,因此它实际上是能够和a.html直接通讯的,假如a.html里面有定义一个方法_callback,在 proxy.html能够直接top._callback()调用它。可是b.html自己和proxy.html也是不能直接通讯的,所谓代理页面的桥 梁做用怎么实现呢? b.html内嵌proxy.html是经过一段相似下面这样的代码: <iframe id=”proxy” src=”a.com/proxy.html” name=”proxy” frameborder=”0″ width=”0″ height=”0″></iframe> 这个iframe的src属性b.html是有权限控制的。若是它把src设置成a.com/proxy.html?args=XXX,也就是给url加 一个查询字符串,proxy.html内的js是能够读取到的。对的,这个url的查询字符串就是b.html和proxy.html之间通讯的桥梁,美 中不足的是每次通讯都要重写一次url形成一次网络请求,这有时会对服务器及页面的运行效率产生很大的影响。同时因为参数是经过url来传递的,会有长度 和数据类型的限制,搜集的资料显示:

  • IE浏览器对URL的长度现限制为2048字节。
  • 360极速浏览器对URL的长度限制为2118字节。
  • Firefox(Browser)对URL的长度限制为65536字节。
  • Safari(Browser)对URL的长度限制为80000字节。
  • Opera(Browser)对URL的长度限制为190000字节。
  • Google(chrome)对URL的长度限制为8182字节。

上面的方法,经过迂回战术实现了b.html跟a.html通讯,可是倒过来,a.html怎么跟b.html通讯呢?嵌入在b.html里面的 proxy.html能够用top快速的联系上a.html,可是要想让a.html找到proxy.html就不容易了,夹在中间的 b.html生生把它们分开了,a.html无法让b.html去找到proxy.html而后返回给它。只能采用更迂回的战术了。 顺着前面b.html到a.html的通讯过程,逆向的想一下,虽然a.html没有办法主动找到proxy.html,可是proxy.html能够反 过来告诉a.html它在哪里: 在proxy.html加这么一段脚本:

在a.html加这么一段脚本:

也就是必须由proxy.html先主动发送一个消息给a.html,a.html获得proxy.html页面window的引用,就能够反过来 向它发送请求了。 如今a.html能够把消息发给proxy.html了,可是proxy.html怎么把消息转送到b.html?彷佛这才是难点,由于它们之间才真正有 着“跨域”这一道鸿沟。 这回咱们再也不用前面那个iframe内嵌代理页面的方法再在proxy.html内嵌一个b.com下面的代理页面了,这样实在会给人感受嵌的太深了,四 层。可是为了跨越这道鸿沟,b.com下面也加一个代理页面是免不的。不过如今咱们要利用一下window.name。window.name有一个特 性,就是页面在同一个浏览器窗口(标签页)中跳转时,它一直存在并且值不会改变。好比咱们在a.html中设置了window.name=”a”,而后 location.href=”http://b.com/b.html”跳转 后,b.html能够读取window.name的值为”a”;并且window.name的值长度通常能够到达2M,ie和firefox甚至能够达到 32M,这样的存储容量,足够利用起来作跨域的数据传递了。好吧,咱们如今要作的就是当proxy.html拿到a.html发送过来的数据后把这个数据 写入window.name中,而后跳转到b.com下面的代理页面,咱们这里假设是bproxy.html。bproxy.html读取到 window.name值后,通知给它父页面b.html就简单了。咱们再来看这个过程能够用图大概示意一下:

跨域

图2

图例中绿色的双向箭头表示能够通讯,橙色的双向箭头表示不能直接通讯。 最后咱们简单看一下双向通讯的实测效果:

跨域

图3

b.html每次加载的时候都先给a.html发一个”链接请求”,让a.html能够找到proxy.html。因此页面第一次加载的时候会产生三个请求:

跨域

图4

每次b.html向a.html发送消息的时候会产生一个请求:

跨域

图5

每次a.html向b.html发送消息的时候会产生两个请求,其中一个是a.com/proxy.html向b.com/bproxy.html跳转产生的,另外一个是b.html从新向a.html发起“链接请求”时产生的:

跨域

图6

最后简单看一下实测的几个测试页面代码: 代码片断一,a.com/a.html:

代码片断二,a.com/proxy.html:

代码片断三,b.com/b.html:

码片断四,b.com/bproxy.html:

好吧,如今我必须把话锋调转一下了。前面讲的这么多,也只是抛出来一些以前咱们可能会采用的跨域通讯方法,事实上代理页面、url传参数和 window.name、甚至还有一些利用url的hash值的跨域传值方法,都能百度到很多相关资料。但它们都逃不开代理页面,也就不可避免的要产生网 络请求,而事实上这并非咱们的本意,咱们本来但愿它们可以直接在客户端通讯,避免没必要要的网络请求开销——这些开销,在访问量超大的站点可能会对服务器 产生至关大的压力。那么,有没有更完美一点的替代方案呢? 必须给你们推荐postMessage。postMessage 正是为了知足一些合理的、不一样站点之间的内容能在浏览器端进行交互的需求而设计的。利用postMessage API实现跨域通讯很是简单,咱们直接看一下实例的代码:

代码片断五,A.com/a.html:

代码片断六,B.com/b.html:

代码的关键是message事件是一个拥有data(数据)和origin(来源)属性的DOM事件。data属性是发送的实际数据,origin 属性是发送来源。Origin属性很关键,有了这个属性,接收方能够轻易的忽略掉来自不可信源的消息,也就能有效避免跨域通讯这个开口给咱们的源安全带来 的隐患。接口很强大,因此代码很简单。咱们能够抓包看一下,这个通讯过程彻底是在浏览器端的,没有产生任何的网络请求。同时这个接口目前已经获得了绝大多 数浏览器的支持,包括IE8及以上版本,参见下面的图表:

跨域

图7

可是为了覆盖ie6等低版本浏览器,咱们完整的方案里面仍是要包含一下兼容代码,就是最开始介绍的代理页面的方法了,但必须是以postMessage为主,这样即使最后会有某些浏览器由于这种通讯产生一些网络请求,比例也是很是低的了。