老生常谈:利用Membership实现SSO(单点登录)

虽然有一些现成的第三方解决方案比如:OpenID,Passport,SpaceCard等都还不错,但是要么就是收费的(passport),要么就是有点用不习惯(比如OpenID),另外中途跳到一个界面完全不相同的第三方站点上输入,用户感觉也不太放心。

当然博客园和csdn上也有不少人已经给出了相应的解决方案,但是一圈看下来,虽然思路都行得通,貌似就是没找到不同主域名下直接利用Membership实现的例子。

那么还是自己“造轮子”弄一个简陋一点的方案吧,其实只要用过Membership的朋友都知道“用户是否已经登录”以及“用户当前的role是什么”等问题的判断依据就是检测客户端有没有(当前要访问)网站(所在域)的cookie票据,如果各子站都在同一个主域下,这么问题很容易解决,只要设置各子域cookie的domain为统一值即可,但如果各子站的主域名不同,这招就失效了(出于安全考虑,浏览器设计时就约定不同主域的cookie不能互访),所以问题的关键是:如何能让用户在某个域成功登录后,自动把本域下的cookie票据同步复制到其它域下!

另外还有用户注销问题,当用户从一个分站注销时其它分站如何注销?其实把上面的思路反过来,也能找到问题的关键:即一个域下的cookie票据清除后,如何能让其它域下的cookie票据也能清除!

根本这个思路,大概整理了一个流程图:


当然还有一些因素要考虑:比如传递敏感参数(比如用户名)时应该加密;同时各分站专用于接收票据和清除票据的页面,如何防止非法访问等等。此外,最好还要求各分站使用同一套统一的用户名/密码表。(当然如果各分站已经有各自的用户数据了,也有办法解决,比如可以新建一套新的统一帐号/密码库,原来各自的分站用户表上加一个字段,映射到新库帐号表的唯一字段)。

示例代码:

1.解决方案结构图

说明:

Passport:认证中心,用于统一登录和注销的类似passport站点

SiteA:站点A,其中admin需要登录才能访问(规则在web.config中配置),passport目录下的login.aspx/loginout.aspx分别用于接收认证中心发来的票据,以及清除票据

SiteB:站点B,结构代码完全同SiteA相同,仅为了与SiteA比较效果用

WebHelper:工具辅助类

2.技术要点:

(a)Cookie同步问题:因为cookie是基于浏览器的,所以直接用代码以Post或Get方式模拟访问SiteA中的/passport/login.aspx以logout.aspx时,并不能正确生成Cookie或清除Cookie,因此我采用了一个变通的办法(隐藏的iframe)来模拟浏览器访问这二个页面

(b)为了尽量使用Membership的功能,少写代码,同时保留membership通过web.config配置目录访问权限的风格,在passport项目中,分别针对各个站点新建A,B...等分站目录,目的仅仅是让ReturnUrl=/Admin/Default.aspx能自动变成类似ReturnUrl=http://www.SiteA.com/Admin/Default.aspx,以便在页面跳转时不需要额外处理

(3)即使是用iframe来实现跨域读写Cookie,默认情况下,如果用户IE浏览器的“隐私”级别设置为中(及中以上)时,浏览器仍然会阻止iframe跨域设置Cookie(所谓的“同域同源”原则,即:当前浏览器的url以及各frame/iframe里面的页面,如果在同一个域名,就能正常实现cookie的读写,否则禁止。单从这一点看,IE其实要比FF之流安全),所以需要在PassPort以及联盟站点的IIS-->Http头中设置相同的P3P协议值(目的是告诉IE:这一组站点相互之间是“朋友”,不要“阻挡”!),具体办法有二种(任选一种即可):

2.1-直接写代码:Response.AddHeader("P3P","CP=\"CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR\"");  把这一行加入要执行Cookie读写的页面的Page_Load事件第一行(注:“CP=”后面的值可以随便设置,只要是一个其它人不知道的string即可,相当于一个密钥)

2.2-IIS站点属性->HTTP头->添加-->自定义HTTP头为 P3P-->自定义HTTP头值为 CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR”-->保存

3.示例代码说明

示例中对于参数的加密采用了Enterprise Library 4.1的加密模块,所以需要安装Enterprise Library才能编译通过

 

欢迎转载,但请注明来自“菩提树下的杨过” http://www.cnblogs.com/yjmyzz/archive/2009/06/03/1495480.html

示例代码下载地址:https://files.cnblogs.com/yjmyzz/SSO.rar

2013/10/3 更新:

利用HttpModule自动拦截机制,把原来各分站的Login.aspx/LoginOut.aspx这些都去掉了,全都在HttpModule拦截处理,同时用script 引用,代替了原来的iFrame机制,新的示例代码地址:https://files.cnblogs.com/yjmyzz/SSO.zip

posted @ 2009-06-03 16:53  菩提树下的杨过  阅读(3187)  评论(0编辑  收藏  举报