做过跨越多个网站的Ajax开发的朋友都知道,如果在A网站中,我们希望使用Ajax来获得B网站中的特定内容,如果A网站与B网站不在同一个域中,那么就出现了跨域访问问题。Ajax的跨域访问问题是现有的Ajax开发人员比较常遇到的问题。
IE对于跨域访问的处理是,弹出警告框,提醒用户。如果用户将该网站纳入可信任网站,或者调低安全级别,那么这个问题IE就不会在提醒你。
FireFox等其它非微软的浏览器遇到跨域访问,则解决方案统一是拒绝访问。
有人说,IE是主流浏览器,只要它能正常使用就好了。此言差已,IE虽然能够处理,但是是有前提的,要么用户不厌其烦地在页面弹出警告框之后点击是(点击否就不执行该Ajax调用了),要么用户将该网站纳入可信任站点。这两种做法,在企业管理系统的应用中倒是比较常见,因为系统管理员可以以行政手段保证用户的行为。但是对于互联网上的网站或者门户开发,这种做法则不行。
最近遇到了这个问题,需要在跨域访问结束之后完成使主窗口出现一些特效,搜索了一些资料,通过不断尝试以及在不同浏览器中进行兼容性测试,找到了几个可行的Web应用跨域访问解决方案:
1、Web代理的方式。
即用户访问A网站时所产生的对B网站的跨域访问请求均提交到A网站的指定页面(Post页面过去),由该页面代替用户页面完成交互,从而返回合适的结果。此方案可以解决现阶段所能够想到的多数跨域访问问题,但要求A网站提供Web代理的支持,因此A网站与B网站之间必须是紧密协作的,且每次交互过程,A网站的服务器负担增加,且无法代用户保存session状态。
2、on-Demand方式。
MYMSN的门户就用的这种方式,不过MYMSN中不涉及跨域访问问题。动态控制script标记的生成,通过修改script标记的src属性完成对跨域页面的调用。此方案存在的缺陷是,script的src属性完成该调用时采取的方式时get方式,如果请求时传递的字符串过大时,可能会无法正常运行。不过此方案非常适合聚合类门户使用。
3、iframe方式。
查看过醒来在javaeye上的一篇关于跨域访问的帖子,他提到自己已经用iframe的方式解决了跨域访问问题。数据提交跟获取,采用iframe这种方式的确可以了,但由于父窗口与子窗口之间不能交互(跨域访问的情况下,这种交互被拒绝),因此无法完成对父窗口效果的影响。
4、用户本地转储方式。
IE本身依附于windows平台的特性为我们提供了一种基于iframe,利用内存来“绕行”的方案,即两个window之间可以在客户端通过windows剪贴板的方式进行数据传输,只需要在接受数据的一方设置Interval进行轮询,获得结果后清除Interval即可。FF的平台独立性决定了它不支持剪贴板这种方式,而以往版本的FF中存在的插件漏洞又被fixed了,所以FF无法通过内存来完成暗渡陈仓。而由于文件操作FF也没有提供支持(无法通过Cookie跨域完成数据传递),致使这种技巧性的方式只能在IE中使用。
5、我自己用于解决这类问题的方式.
结合了前面几种方式,在访问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相同)。
该方案特点:
1、不能够跨域
2、在网络中传送用户名和密码
3、只支持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 文件,内容如下:
//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 文件,内容如下:
var_dump($_COOKIE);
?>
最后:创建 b_setcookie.php 文件,内容如下:
----------------------------
三个文件创建完毕后,我们通过浏览器依次访问:
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即为:
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又是与域名相关的,所以采用这个方案的各个服务器需要有相同的域名(至少是相同的二级域名),比如:
1、所有服务器的域名都是www.whybsd.com,这个东东DNS轮询就可以实现;这个时候,在PHP中将Cookie域名设置为www.whybsd.com即可;
2、所有服务器的域名都是以.whybsd.com结尾的三级域名,比如a.whybsd.com,b.whybsd.com等等,这个时候,在PHP中将Cookie域名设置为.whybsd.com就可以共享Cookie了。
解决了先决条件,我们现在来看看PHP的Session存储方法,在PHP手册说明中,有一个叫session_set_save_handler()的函数,这个函数是用来注册用户自定义的Session数据存储接口的。
以下是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)就可以了。
嗯,比较简单,而且经济。
更多考虑:
1、性能需要考量,特别是服务器数(引起资源占用)和用户量(引起Session量)非常巨大的时候。
==========================================================
PHP实现WebServices和跨域自动登陆
1、webservices的php实现
主要是基于nusoap这个库来实现的,其不但可以实现server功能还可以实现client功能,支持end point和WSDL两种方式;连soap协议的xml消息都是自己解析的,所以完全可以脱离其他php库支持;优点之一啊;可惜,可能有性能上的忧虑。
2、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跨域认证解决方法:
1、架设一个PASSPORT服务器(该服务器命名为A)。所有的用户验证都通过此服务器验证,其他服务器对用户信息的获取,用户的身份确认,都要通过这个服务器来实现。
2、在应用服务器(该服务器命名为B)的所有需要验证的地方判断用户信息是否已经验证,如果没有验证,则通过 IFRAME 在用页面放一个A服务器的验证页面,并传递一个A可以识别的标记参数,告诉A服务器是B服务器需要验证当前用户。
3、A服务器获得B服务器的页面请求后,首先检查当前用户是否登陆,如果没有登陆,则停止验证,或者反馈一个尚未登陆的页面。
4、如果A用户收到B服务器的也面请求后,发现当前用户已经登陆,则生成一个随机的长的字符串并在记录下该字符串、生成时间、对应的用户记录、B服务器的标记。然后通过自动跳转技术,访问B服务器上的一个用户信息验证页面,同时传递所生成的长字符串。(该页面由A从自身记录中获取,由事先录入);
5、B服务器的验证页面收到到所传递的长字符串后,在服务器端访问A服务器的服务器端信息确认页面,同时传递所收到的长字符串以及服务器标识。
6、A服务器的服务器端信息确认页面收到信息后,通过字符串与发出请求的服务器来验证信息的正确性:
(1)首先判断服务器IP是否属于该PASSPORT的服务服务器列表;
(2)通过字符串查询记录中是否有该字符串;
(3)通过请求服务器的IP与保留的服务器标记核对,看是否请求的IP地址是当前记录的服务器的;
(4)判断字符串的生成时间与当前时间比较,是否超时,超时的设置,在A服务器上设置;
(5)如果都核对无误,则返回对应的用户信息,否则反馈错误信息;
7、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
$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, == 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
print $_COOKIE['test'];
?>
A_setcookie.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
由于同源策略的限制,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 |
不同域名 |
不允许 |
其中编号6、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的src属性b.html是有权限控制的。如果它把src设置成a.com/proxy.html?args=XXX,也就是给url加 一个查询字符串,proxy.html内的js是可以读取到的。对的,这个url的查询字符串就是b.html和proxy.html之间通信的桥梁,美 中不足的是每次通信都要重写一次url造成一次网络请求,这有时会对服务器及页面的运行效率产生很大的影响。同时由于参数是通过url来传递的,会有长度 和数据类型的限制,搜集的资料显示:
上面的方法,通过迂回战术实现了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为主,这样即便最后会有某些浏览器因为这种通信产生一些网络请求,比例也是非常低的了。
转自:http://tid.tenpay.com/?p=4695