技术开发 频道

[译]SSO解决方案大全

  【IT168 技术文档】前段时间为我们的系统做SSO(单点登录)参考了很多资料,其中包括博客园二级域名的登录.翻译本文是由于作者的一句话:思想都是一样的,只不过实现起来需要创造性思维.

  Single Sign-On (SSO)是近来的热门话题. 很多和我交往的客户中都有不止一个运行在.Net框架中的Web应用程序或者若干子域名.而他们甚至希望在不同的域名中也可以只登陆一次就可以畅游所有站点.今天我们关注的是如何在各种不同的应用场景中实现 SSO. 我们由简到繁,逐一攻破.

  虚拟目录的主应用和子应用间实现SSO
  使用不同验证机制实现SSO  (username mapping)
  同一域名中,子域名下的应用程序间实现SSO
  运行在不同版本.NET下的应用程序间实现SSO
  两个不同域名下的Web应用程序间实现SSO
  混合身份验证方式模式 (Forms and Windows)下实现SSO
 

  1. 虚拟目录的主应用和子应用之间实现SSO

  假设有两个.Net的Web应用程序-Foo和Bar,Bar运行在Foo虚拟目录的子目录(http://foo.com/bar).二者都实现了Forms认证.实现Forms认证需要我们重写Application_AuthenticateRequest,在这个时机我们完成认证一旦通过验证就调用一下FormsAuthentication.RedirectFromLoginPage.这个方法接收的参数是用户名或者其它的一些身份信息.在Asp.net中登录用户的状态是持久化存储在客户端的cookie中.当你调用RedirectFromLoginPage时就会创建一个包含加密令牌FormsAuthenticationTicket的cookie,cookie名就是登录用户的用户名.下面的配置节在Web.config定义了这种cookie如何创建:

  比较重要的两个属性是 name 和protection. 按照下面的配置就可以让Foo和Bar两个程序在同样的保护级别下读写Cookie,这就实现了SSO的效果:

<authentication mode="Forms">
<forms name=".SSOAuth" protection="All" timeout="60" loginUrl="login.aspx" />
</authentication>

 

  当 protection属性设置为 "All",通过Hash值进行加密和验证数据都存放在Cookie中.默认的验证和加密使用的Key都存储在machine.config文件,我们可以在应用程序的Web.Config文件覆盖这些值.默认值如下:

<machineKey validationKey="AutoGenerate,IsolateApps" decryptionKey=" AutoGenerate,IsolateApps" validation="SHA1" />

 

  IsolateApps表示为每个应用程序生成不同的Key.我们不能使用这个.为了能在多个应用程序中使用相同的Key来加密解密cookie,我们可以移除IsolateApps 选项或者更好的方法是在所有需要实现SSO的应用程序的Web.Config中设置一个具体的Key值:  

<machineKey validationKey="F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902" decryptionKey="F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902F8D923AC" validation="SHA1" />

  如果你使用同样的存储方式,实现SSO只是改动一下Web.config而已.

  2.使用不同认证机制实现SSO (username mapping)

  要是FOO站点使用database来做认证,Bar站点使用Membership API或者其它方式做认证呢?这种情景中FOO站点创建的cookie对Bar站点毫无用处,因为cookie中的用户名对Bar没有什么意义.

  要想cookie起作用,你就需要再为Bar站点创建一个认证所需的cookie.这里你需要为两个站点的用户做一下映射.假如有一个Foo站点的用户"John Doe"在Bar站点需要识别成"johnd".在Foo站带你你需要下面的代码:

FormsAuthenticationTicket fat = new FormsAuthenticationTicket(1, "johnd", DateTime.Now, DateTime.Now.AddYears(1), true, "");
HttpCookie cookie = new HttpCookie(".BarAuth");
cookie.Value = FormsAuthentication.Encrypt(fat);
cookie.Expires = fat.Expiration;
HttpContext.Current.Response.Cookies.Add(cookie);
FormsAuthentication.RedirectFromLoginPage("John Doe");

为了演示用户名硬编码了.这个代码片段为Bar站点创建了令牌FormsAuthenticationTicket ,这时令牌里的用户名在Bar站点的上下文中就是有意义的了. 这时再调用 RedirectFromLoginPage创建正确的认证cookie.上面的例子你统一了了Forms 认证的cookie名字,而这里你要确保他们不同--因为我们不需要两个站点共享相同的cookie:

<authentication mode="Forms">
  
<forms name=".FooAuth" protection="All" timeout="60" loginUrl="login.aspx" slidingExpiration="true"/>
</authentication>
<authentication mode="Forms">
  
<forms name=".BarAuth" protection="All" timeout="60" loginUrl="login.aspx" slidingExpiration="true"/>
</authentication>

现在当用户在Foo站点登录,他就会被映射到到Bar站点的用户并同时创建了Foo和Bar两个站点的认证令牌.如果你想在Bar站点登录在Foo站点通行,那么代码就会是这样:

FormsAuthenticationTicket fat = new FormsAuthenticationTicket(1, "John Doe", DateTime.Now, DateTime.Now.AddYears(1), true, "");
HttpCookie cookie = new HttpCookie(".FooAuth");
cookie.Value = FormsAuthentication.Encrypt(fat);
cookie.Expires = fat.Expiration;
HttpContext.Current.Response.Cookies.Add(cookie);
FormsAuthentication.RedirectFromLoginPage("johnd");

同样要保证两个站点的Web.config的<machineKey>配置节有相同的加密和解密的Key!

 

0
相关文章