老生常谈:利用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://files.cnblogs.com/yjmyzz/SSO.rar

2013/10/3 更新:

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏眯眯眼猫头鹰的小树杈

vue-cli的项目结构

这篇文章对纯新手友好,所以有过任何vue开发经验的人可以出门左转啦!这篇文章献给我的homie苏蕾儿童鞋,让她在学习vue项目的时候少走一点弯路(径直冲向末路哈...

2354
来自专栏散尽浮华

Saltstack自动化操作记录(1)-环境部署

早期运维工作中用过稍微复杂的Puppet,下面介绍下更为简单实用的Saltstack自动化运维的使用。 Saltstack知多少 Saltstack是一种全新的...

26110
来自专栏Theo Tsao

Ionic3学习笔记(十三)HttpClient 实现 HTTP 请求以及踩过的一些坑

当然是基于这篇古老的文章啦 ==> http://www.jianshu.com/p/9855610eb1d4 因为是2015年的文章,已经时隔2年多,很难确保...

4361
来自专栏黑泽君的专栏

网络通信的三要素

6024
来自专栏逸鹏说道

NET跨平台:在Ubuntu下搭建ASP.NET 5开发环境

0x00 写在前面的废话 年底这段时间实在太忙了,各种事情都凑在这个时候,没时间去学习自己感兴趣的东西,所以博客也好就没写了。最近工作上有个小功能要做成Web应...

2983
来自专栏大魏分享(微信公众号:david-share)

Openshift 3.11的14大新功能详解

聂健是大魏的红帽同事,本文已获得授权转载,欢迎读者阅读他的技术blog:https://www.cnblogs.com/ericnie/

1.1K3
来自专栏拂晓风起

cocos2d-js 调试办法 断点调试 Android真机调试

1802
来自专栏恰同学骚年

.NET Core微服务之基于EasyNetQ使用RabbitMQ消息队列

  “消息”是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;也可以更复杂,可能包含嵌入对象。消息被发送到队列中,“消息队列”是在消息的传...

8355
来自专栏Eugene's Blog

黑客常用的扫描器盒子分类目录文章标签友情链接联系我们

2779
来自专栏知识分享

八,ESP8266 文件保存数据(基于Lua脚本语言)

应该是LUA介绍8266的最后一篇,,,,,,下回是直接用SDK,,然后再列个12345.......不过要等一两个星期,先忙完朋友的事情 前面几篇 用AT指令...

3977

扫码关注云+社区

领取腾讯云代金券