ASP.NET MVC 2和使用WIF(Windows身份基础)进行身份验证

23

是否有以下方面的良好示例可用:

浏览WIF SDK,有使用WSFederationAuthenticationModule (FAM)将WIF与ASP.NET结合使用的示例,以重定向到在安全令牌服务(STS)之上的ASP.NET网站,并在其上使用“薄皮”进行身份验证(通过提供用户名和密码)。

如果我正确理解了WIF和基于声明的访问,我希望我的应用程序提供自己的登录屏幕,让用户提供其用户名和密码,并允许此代表STS进行身份验证,通过安全标准(WS-*)将登录详细信息发送到端点,并期望返回SAML令牌。理想情况下,SessionAuthenticationModule将按照使用FAMSessionAuthenticationModule一起使用的示例工作,即负责从会话安全分块cookie重建IClaimsPrincipal并在安全会话过期时重定向到我的应用程序登录页面。

我所描述的使用适当的web.config设置使用FAMSessionAuthenticationModule是否可行,还是我需要考虑编写自己的HttpModule来处理这个问题?或者,在被动请求者场景中,重定向到一个薄的网站STS,在那里用户登录是事实上的方法?

5个回答

19

“声明标识指南”中的本章提供了WIF + MVC的示例:

http://msdn.microsoft.com/en-us/library/ff359105.aspx

我建议阅读前几章以理解所有基本原则。这篇博客文章涵盖了有关MVC + WIF的详细信息:

链接

控制登录体验是完全可以的。您应该部署自己的STS(在您的域中,具有您的外观和感觉等)。您的应用程序只需依赖它进行身份验证(这就是为什么应用程序通常称为“受信方”的原因)。

此架构的好处是将AuthN委托给1个组件(STS),而不是分散在许多应用程序中。但另一个(巨大的)优点是,您可以很容易地启用更复杂的场景。例如,您现在可以与其他组织的标识提供者联合。

希望有所帮助 Eugenio

@RisingStar:

令牌(包含声明)可以选择加密(否则它们将以明文形式显示)。这就是为什么始终建议在浏览器和STS之间的交互中使用SSL的原因。

请注意,即使它们是明文,篡改也是不可能的,因为令牌已经数字签名。


谢谢Eugenio,我以为我已经看过了Claims Identity指南,但显然没有,因为我错过了Fabrikam是一个MVC应用程序。我会再去看一下的。我也看了Dominick Baier的博客,认为从Web服务器在登录页面上调用活动STS是我最终想要的。 - Russ Cam
我认为在ASP.net MVC中使用WIF与使用ASP.net表单没有任何区别。 - Vivian River
1
原则完全相同,只有一些实现细节不同。最常见的区别是:
  • 在 WebForms 应用程序中,您通常依赖 WIF 进行所有协议交换(passiveRedirectEnable=true)。在 MVC 应用程序中,您将关闭它,并根据我的博客文章中所述以编程方式处理它。
  • 在 MVC 应用程序中,您通常会实现一个 IAuthorizationFilter 属性。在 Web Forms 中,这不存在,您只需依赖现有的 ASP.NET 授权机制(或调用 IsInRole 等)。
- Eugenio Pace

13

这是一个有趣的问题。我知道,出于某种原因,微软发布了这个“Windows Identity Foundation”框架,但并没有提供太多文档。我知道这一点是因为我被分配任务去解决如何在新项目中使用它并将其与现有基础设施集成。我已经在网上搜索了几个月以寻找好的信息。

我采取了一种不同的方法来解决你描述的问题。

我将Microsoft的WIF管道集成到现有的登录应用程序中。也就是说,我有一个应用程序,用户登录。登录应用程序提交用户提供的凭据到另一个服务器,该服务器返回用户身份(或指示登录失败)。

查看了Microsoft的一些示例之后,我发现他们做了以下事情:

从查询字符串(由依赖方应用程序生成),构建一个SignInRequestMessage,从自定义类构建安全令牌服务,最后使用当前httpcontext.response调用FederatedSecurityTokenServiceOperations.ProcessSignInresponse。不幸的是,我不能在这里很好地解释它;你确实需要查看代码示例。

我的一些代码与代码示例非常相似。你将有兴趣在GetOutputClaimsIdentity中实现大量自己的逻辑。这是构建描述已登录用户的声明标识的函数。

现在,这就是我认为你真正想知道的。据我所知,这是微软在他们的文档中没有告诉你的。

一旦用户登录,他们将被重定向回依赖方应用程序。不管登录应用程序如何工作,WIF类都会向用户的浏览器发送响应,其中包含一个“隐藏”的HTML输入,其中包含令牌签名证书和用户的声明(声明将以明文形式呈现)。在此响应的末尾,将重定向到你的依赖方网站。我之所以知道这个动作,是因为我用“Fiddler”捕获了它。

一旦返回到依赖方网站,WIF类将处理响应(在运行任何代码之前)。证书将被验证。默认情况下,如果您使用FedUtil.exe(通过从Visual Studio中的依赖方应用程序点击“添加STS引用”)设置了依赖方网站,则Microsoft的类将验证证书指纹。

最后,WIF框架会在用户的浏览器中设置cookie(根据我的经验,cookie名称始于“FedAuth”),其中包含用户的声明。这些cookie不可读。

一旦发生这种情况,您可以选择使用ClaimsAuthenticationClass在依赖方网站上对用户的声明执行操作。这是您的代码再次运行的地方。

我知道这与您所描述的不同,但我已使此设置工作。我希望这有所帮助!

附:请查看我关于Windows Identity Foundation的其他问题。

更新:回答下面评论中的问题:

我忘了一件事,重定向到STS登录应用程序是通过包含用户正在登录的应用程序的URL的查询字符串进行的重定向。第一次尝试访问需要身份验证的页面时,此重定向会自动发生。或者,我相信您可以使用WSFederationAuthentication模块手动执行重定向。

我从未尝试过这样做,但如果您想在应用程序本身中使用登录页面,则我认为框架应该允许您使用以下内容:

1)将STS代码封装在库中。 2)从应用程序引用库。 3)在应用程序中创建一个登录页面。确保此类页面不需要身份验证。 4)将web.config的Microsoft.IdentityModel部分中的wsFederation元素的发行者属性设置为登录页面。


感谢您抽出时间回答我的问题。我已经查看了随 WIF SDK 一起提供的编译的 HTML 帮助文件,并浏览了所有示例。我使用 Reflector 分析了 FAMSessionAuthenticationModule,并认为我已经很好地掌握了它的工作原理,但我很想看看是否有使用 FAM 或自定义 HttpModule 与基于声明的身份验证的 SessionAuthenticationModule 结合使用的示例。FAM 看起来很容易使用,但不提供太多灵活性... - Russ Cam
1
也许整个想法是登录应该在Web应用程序STS上进行,因为这意味着您不需要担心在每个Web应用程序中构建登录屏幕。但是,我希望能够为每个应用程序保留特定的外观和感觉,并且最好将其保留在同一域中,以避免混淆用户(可能会发生,因为有很多非技术人员)。我只想获取输入的凭据,将它们包装在WS-Federated调用中,以进行身份验证。我的想法是否与这个想法不符? - Russ Cam
你的想法并不一定是错的。我开始时已经有一个用于其他应用程序的单独登录应用程序;我只是将STS添加到登录应用程序中。我相信你想做的是可能的,但需要一些实验才能使其正常运行。我更新了我的答案,并提出了一个你可能会让它工作的想法。 - Vivian River
你似乎很熟悉在ASP.NET MVC中使用WIF。我正在研究如何使用WIF来集成MVC应用程序和WebForms应用程序。我已经下载了SDK,但我不确定从哪里开始。这些应用程序中的每一个都有自己的登录页面,我想设置这样一个机制:任何进入第一个应用程序的登录页面的请求都将被传递到STS进行身份验证和授权。一旦用户登录第一个应用程序,他们就可以跳过第二个应用程序的登录页面。在这种情况下,你建议我看哪个示例? - DotnetDude
@DotnetDude,看看这个身份验证“开发者培训套件”,如果你在使用它时遇到问题,请务必查看此讨论:http://stackoverflow.com/questions/2052386/getting-windows-identity-foundation-developer-training-kit-examples-to-work。其中有一个示例展示了如何使用WIF将用户登录到多个网页。 - Vivian River

4
您想要做的是主动登录。WIF包括WSTrustChannel(Factory),它允许您直接与STS通信并获取安全令牌。如果您希望您的登录表单以这种方式工作,可以按照WIF 4.0 SDK中的"WSTrustChannel"示例进行操作。一旦您获得了令牌,以下代码将使用该令牌调用WIF处理程序以创建会话令牌并设置适当的cookie:
public void EstablishAuthSession(GenericXmlSecurityToken genericToken)
{
    var handlers = FederatedAuthentication.ServiceConfiguration.SecurityTokenHandlers;            
    var token = handlers.ReadToken(new XmlTextReader(
                                        new StringReader(genericToken.TokenXml.OuterXml)));

    var identity = handlers.ValidateToken(token).First();
    // create session token
    var sessionToken = new SessionSecurityToken(
        ClaimsPrincipal.CreateFromIdentity(identity));
    FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
}

完成此操作后,您的网站应该表现得与被动签名发生时相同。

1
你可以使用FederatedPassiveSignIn控件。

这是一个适用于WebForms的服务器端控件,但自然不适用于MVC应用程序(因为它是具有runat="server"属性的服务器端控件)。对此有什么建议吗? - atconway

0

像这样设置您的cookie: FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken); 对于跨域SSO无效。

应该由STS而不是RP设置cookie。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接