Joh*_*ohn 20 .net claims-based-identity wif .net-4.5
在过去的几天里,我一直在阅读关于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>
Run Code Online (Sandbox Code Playgroud)
但是,认证管理器永远不会被调用.我可以通过以下方式添加:
protected void Application_PostAuthenticateRequest()
{
ClaimsPrincipal currentPrincipal = ClaimsPrincipal.Current;
ClaimsTransformationModule customClaimsTransformer = new MyClaimsTransformationModule();
ClaimsPrincipal tranformedClaimsPrincipal = customClaimsTransformer.Authenticate(string.Empty, currentPrincipal);
HttpContext.Current.User = tranformedClaimsPrincipal;
}
Run Code Online (Sandbox Code Playgroud)
到我的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);
Run Code Online (Sandbox Code Playgroud)
但我也不确定那部分,转换问题需要先修复.
任何帮助,将不胜感激.只需要调用查找/转换和cookie集,谢谢.
Joh*_*ohn 19
我现在一切都在运作,这就是我如何去做的:
在此页面上:http://msdn.microsoft.com/en-us/library/ee517293.aspx是关键段落:
如果您想使您的RP应用程序声明感知,但您没有STS(例如,RP使用Forms身份验证或Windows集成身份验证),则可以使用ClaimsPrincipalHttpModule.该模块位于应用程序的HTTP管道中,并拦截身份验证信息.它根据用户的用户名,组成员身份和其他身份验证信息为每个用户生成IClaimsPrincipal.ClaimsPrincipalHttpModule必须插入
<httpModules>管道的末尾,这是IIS 7<modules>部分中的第一个元素<system.webServer>.
而这个页面:
给你全班:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在将该类添加到web.config:
<modules>
<add name="ClaimsTransformationHttpModule" type="TestSecurity.ClaimsTransformationHttpModule" />
</modules>
Run Code Online (Sandbox Code Playgroud)
现在它将调用转换,我可以删除global.asax中的post authenticate方法.
在authenticate方法中,我调用它来设置cookie:
private void CreateSession(ClaimsPrincipal transformedPrincipal)
{
SessionSecurityToken sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
}
Run Code Online (Sandbox Code Playgroud)
之前的模块已经设置为查看它并跳过身份验证(如果存在).
最后是我一直得到的安全句柄错误.我不确定原因,但我发现如果我修改了传递给Authenticate然后返回它的主体(它在msdn上显示的内容),那么错误将显示在所有后续请求中.但是,如果我创建并返回一个新的主体,那么它就不会发生.这对于删除不需要的声明也很有用.
List<Claim> newClaims = new List<Claim>();
var keeper = ((ClaimsIdentity)incomingPrincipal.Identity).Claims.First(c =>
c.Type == ClaimTypes.Name);
newClaims.Add(keeper);
ClaimsIdentity ci = new ClaimsIdentity(newClaims, "Negotiate");
return new ClaimsPrincipal(ci);
Run Code Online (Sandbox Code Playgroud)
所以现在我可以对Windows进行身份验证,引入自定义声明,并使用cookie缓存它们.希望这有助于其他人尝试做同样的事情,如果我没有做正确的事,请告诉我.
Phi*_*rdt 11
这个答案旨在进一步澄清约翰上面的答案,经历了几个令人沮丧的日子,试图解决一些类似的问题.
正如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都应该没问题.