代码改变世界

实现基于 ASP.NET Forms 身份验证的跨子域单点登录

2010-03-14 21:54 by 晓风残月, ... 阅读, ... 评论, 收藏, 编辑

对于跨应用程序的 ASP.NET Forms 身份验证,相信大家应该都不陌生,几年前很多文章都介绍了如何实现,比如 MSDN 的 跨应用程序进行 Forms 身份验证唐朝程序员ASP.NET站点跨子域名单点登陆(SSO)的实现dudu关于二级域名Cookie的问题及解决方法。这个方案实际上利用了 cookie 可以跨子域共享,当前几乎所有主流器包括 IE6+/FF3/Opera9/Chrome 都支持此特性。但这些文章所介绍的都仅仅是“共享身份票据 cookie ”,而没有“共享登录中心”,也就是说,每个应用程序(站点)都具有自己的 login 实现,只是实现过程确保身份票据 cookie 具有相同的 domain 等属性。如此似乎没有实现完全意义上的 SSO,而且每个站点需要维护自己的登录验证代码,当然对于 跨应用程序进行 Forms 身份验证 提到的“网络场”这个问题不大,因为这些站点其实都是一份程序的副本而已。那么,假如我们希望实现像 Windows Live 一样只有一个统一的登录验证中心呢?比如我们规划了以下四个个站点:

http://www.ssolab01.leoworks.net 主站站点
http://news.ssolab01.leoworks.net 新闻频道
http://forum.ssolab01.leoworks.net 论坛社区
http://passport.ssolab01.leoworks.net 通行证中心

其中 http://passport.ssolab01.leoworks.net 作为通行证中心,只在该站点中的 http://passport.ssolab01.leoworks.net/login.aspx 实现登录验证逻辑。假如需要身份验证,其他站点则跳转这个站点进行验证,验证通过之后再跳转到原始请求连接。

大家肯定会觉得很简单,认为只要在子站点中的 web.config 将 forms 元素的 login 设置为 http://passport.ssolab01.leoworks.net/login.aspx 应就可以了,其实不然。没错,如果不用内置缺省 ASP.NET Forms 验证(通过 FormsAuthenticationModule),就像在 ASP/JSP/PHP 中,完全手动实现,逻辑上很清晰只是代码量问题。但是,一经 FormsAuthenticationModule 以及实用类 FormsAuthentication 包装与过滤,两个大问题就来了:

1. 支持重定向的 returnUrl 参数包含的是原始请求的相对路径,而不是包含站点主机的完整路径。这在同一个站点内没问题,但是跨站点的时候,登录成功就回不去了。

2. 当手动将 returnUrl 补上完整的主机路径,虽然登录成功,但竟然直接重定向到 http://passport.ssolab01.leoworks.net

搜索了半天终于发现解决方案:

对于问题2,比较容易,ASP.NET 2.0 已支持,只要在 forms 元素内设置 enableCrossAppRedirects="true" 。注意这只要在 passport 站点内设置即可,因为 passport 负责跳回原始请求。

passport  的 web.config

        
            
        
        
            
            
        
        

 

www 或 forum 的 web.config

        
            
        
        
            
            
        
        

对于问题1,需要手动检查用户是否有权限访问目标资源,如果没有重定向到 http://passport.ssolab01.leoworks.net/login.aspx 页面,并带上完整的原始请求地址作为 returnUrl 参数。检查的时机选择在 PostAuthenticateRequest 事件内。检查逻辑可使用 UrlAuthorizationModule.CheckUrlAccessForPrincipal 方法(注意 ASP.NET 2.0+ 支持)。可以单独写一个 HttpModule 或者直接放入 Global.asax 中。注意这只要在子站点中实现,passport 站点不需要,因为 passport 是站内跳转。

<%@ Application Language="C#" %>

附件是完整的测试示例,注意使用说明:

1. 建立 IIS 网站

在 IIS 中建立三个网站,主机头分别设为:

http://www.ssolab01.leoworks.net
http://forum.ssolab01.leoworks.net
http://passport.ssolab01.leoworks.net

目录分别指向:

Central
Forum
Passport

2. 解析 DNS
用记事本打开 C:\Windows\System32\drivers\etc\hosts 文件

添加三条记录

127.0.0.1    passport.ssolab01.leoworks.net
127.0.0.1    www.ssolab01.leoworks.net
127.0.0.1    forum.ssolab01.leoworks.net

本机使用 127.0.0.1 即可,若是局域网其他客户端的 hosts 则使用安装以上三网站的主机 IP 地址

下载

LeoLab.SSO.FormsAuthCrossSubdomain.zip (15.46 kb)

原文镜像:实现基于 ASP.NET Forms 身份验证的跨子域单点登录