在过去的几天里,我一直在阅读关于Windows身份基础以及它如何如此优秀和灵活并且内置于.net 4.5的内容。尽管经历了几十个api,博客文章,操作方法等等,但我无法为我的生活做一个简单的实现工作。
我只使用Windows身份验证,我可以获取主体并查看随附的声明(这是每个示例似乎结束的地方)。但是,我想将它们转换为有用的声明并缓存结果,以便每次请求都不会发生转换。
在我的web.config中,我有:
<configSections>
<section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</configSections>
<system.identityModel>
<identityConfiguration>
<claimsAuthenticationManager type="SecurityProj.MyClaimsTransformationModule,SecurityProj" />
<claimsAuthorizationManager type="SecurityProj.MyClaimsAuthorizationManager,SecurityProj" />
</identityConfiguration>
</system.identityModel>
然而,身份验证管理器永远不会被调用。我可以通过添加:
来获得它的唯一方法protected void Application_PostAuthenticateRequest()
{
ClaimsPrincipal currentPrincipal = ClaimsPrincipal.Current;
ClaimsTransformationModule customClaimsTransformer = new MyClaimsTransformationModule();
ClaimsPrincipal tranformedClaimsPrincipal = customClaimsTransformer.Authenticate(string.Empty, currentPrincipal);
HttpContext.Current.User = tranformedClaimsPrincipal;
}
到我的global.asax.cs文件。它适用于第一个请求,但之后我得到“安全句柄已关闭”错误,并且不知道是什么导致它。显然,这不是正确的方法,所以有谁知道什么是最好或简单的工作实践?这仅适用于Windows身份验证,我不需要更复杂的东西。
对于缓存,我试图使用:
SessionSecurityToken token = FederatedAuthentication.SessionAuthenticationModule
.CreateSessionSecurityToken(
currentPrincipal,
"Security test",
System.DateTime.UtcNow,
System.DateTime.UtcNow.AddHours(1),
true);
if (FederatedAuthentication.SessionAuthenticationModule != null &&
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies))
{
return;
}
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(token);
但我也不确定那部分,转换问题需要先解决。
任何帮助将不胜感激。只需要调用查找/转换和cookie集,谢谢。
答案 0 :(得分:19)
我现在已经完成了所有工作,以下是我的工作方式:
在此页面上:http://msdn.microsoft.com/en-us/library/ee517293.aspx是关键段落:
如果您想让您的RP应用程序声明感知,但您没有STS(例如,RP使用Forms身份验证或Windows集成身份验证),则可以使用ClaimsPrincipalHttpModule。该模块位于应用程序的HTTP管道中,并拦截身份验证信息。它根据用户的用户名,组成员身份和其他身份验证信息为每个用户生成IClaimsPrincipal。 ClaimsPrincipalHttpModule必须插入
<httpModules>
管道的末尾,这是IIS 7上<modules>
的{{1}}部分中的第一个元素。
这页:
给你全班:
<system.webServer>
现在将该类添加到web.config:
public class ClaimsTransformationHttpModule : IHttpModule
{
public void Dispose()
{ }
public void Init(HttpApplication context)
{
context.PostAuthenticateRequest += Context_PostAuthenticateRequest;
}
void Context_PostAuthenticateRequest(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
// no need to call transformation if session already exists
if (FederatedAuthentication.SessionAuthenticationModule != null &&
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(context.Request.Cookies))
{
return;
}
var transformer =
FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
if (transformer != null)
{
var transformedPrincipal = transformer.Authenticate(context.Request.RawUrl, context.User as ClaimsPrincipal);
context.User = transformedPrincipal;
Thread.CurrentPrincipal = transformedPrincipal;
}
}
}
现在它将调用转换,我可以删除global.asax中的post authenticate方法。
在authenticate方法中,我调用它来设置cookie:
<modules>
<add name="ClaimsTransformationHttpModule" type="TestSecurity.ClaimsTransformationHttpModule" />
</modules>
之前的模块已经设置为查看它并跳过身份验证(如果存在)。
最后是我一直得到的安全句柄错误。我不确定原因,但我发现如果我修改了传递给Authenticate然后返回它的主体(它在msdn上显示的内容),那么错误将显示在所有后续请求中。但是,如果我创建并返回一个新的主体,那么它就不会发生。这对于删除不需要的声明也很有用。
private void CreateSession(ClaimsPrincipal transformedPrincipal)
{
SessionSecurityToken sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
}
所以现在我可以对Windows进行身份验证,引入自定义声明,并使用cookie缓存它们。希望这有助于其他人尝试这样做,如果我没有做正确的事,请告诉我。
答案 1 :(得分:10)
这个答案旨在进一步澄清约翰上面的答案,经历了几个令人沮丧的日子,试图解决一些类似的问题。
正如John所发现的,如果您使用的是Windows Auth或Forms Auth,ASP.NET将不会自动调用您的ClaimsAuthenticationManager(它不是联合方案)。在ASP.NET对用户进行身份验证后,您必须自己执行此操作。使用ClaimsPrincipalHttpModule(曾经是IdentityModel的一部分)将有效地确保发生这种情况。
但是,请谨慎使用此模块。它被移除是有原因的。我从IdentityModel中删除它的理由是因为如果你在ASP.NET应用程序中托管WCF服务并且aspNetCompatibilityEnabled = true,它就不能很好地运行。它将导致您的WCF身份验证中断(模块将在WCF管道之前执行,我的经验是您的WCF客户端将无法再正确进行身份验证 - 我在使用Windows Auth时已经确认了这一点)。
如果您在此方案中托管WCF服务,则必须以某种方式确保仅针对非WCF请求调用ClaimsAuthenticationManager。对于WCF请求,您似乎必须依赖WCF管道(<serviceCredentials useIdentityConfiguration="true" />
)。最简单的解决方法是简单地关闭aspNetCompatibilityEnabled。如果这不是一个选项,则不应使用ClaimsPrincipalHttpModule,但必须以某种方式检查传入请求,并且只有在请求不是以WCF为目的地时才调用ClaimsAuthenticationManager。
如果您创建基于WindowsIdentity的SessionSecurityToken,则会发生这种情况。 SessionAuthenticationModule具有处理从SessionSecurityToken读取的WindowsIdentity声明的特殊逻辑,并将尝试使用不再有效的数据重新水化WindowsIdentity。 (我不确定它会起作用的情况,但在我测试的所有场景中它总是失败)。因此,正如John解释的那样,这里的教训是,当尝试在Windows身份验证中使用WIF时,不应从WindowsPrincipal(或更正确的WindowsIdentity)创建SessionSecurityTokens。任何其他类型的转换的ClaimsPrincipal应该没问题。