我目前正在使用windows azure活动目录作为我的MVC.NET应用程序中的单点登录,并且该部分效果很好。我可以对WAAD进行身份验证,并且可以毫无问题地加载我的ClaimsPrinicipal。
下一步是通过添加来自不同数据源的新声明来转换从WAAD检索到的声明。在这种程度上,我创建了一个继承ClaimsAuthenticationManager的类(如下所示)。声明会添加到Principal中,并在CreateSession方法中持久保存到会话cookie。
我现在的问题是,ClaimsPrincipal.Current不会带有我添加的任何其他声明。当我在SessionAuthenticationModule_SessionSecurityTokenReceived事件中设置断点时,我可以看到ClaimsPrincipal.Current
之间存在差异。ClaimsPrincipal.Current.FindAll(ClaimTypes.Email)
Count = 0
和e.SessionToken.ClaimsPrincipal。
e.SessionToken.ClaimsPrincipal.FindAll(ClaimTypes.Email)
Count = 1
[0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress: me@mydomain.com}
我在这里缺少什么?在处理转换声明的所有样本中,我都没有提到从cookie中手动重新加载ClaimsPrinicipal。会话安全令牌事件是否是重新加载ClaimsPrincipal的正确位置,还是我打破了安全模型?
感谢。
public class MyAuthenticationManager : ClaimsAuthenticationManager
{
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (!incomingPrincipal.Identity.IsAuthenticated)
{
return base.Authenticate(resourceName, incomingPrincipal);
}
var transformedPrincipal = this.CreateUserPrincipal(incomingPrincipal.Identity.Name);
this.CreateSession(transformedPrincipal);
return transformedPrincipal;
}
private ClaimsPrincipal CreateUserPrincipal(String userName)
{
List<Claim> claims = new List<Claim>();
var user = SecurityController.GetUserIdentity(userName);
claims.Add(new Claim(ClaimTypes.Name, userName));
claims.Add(new Claim(ClaimTypes.Email, user.Email));
claims.Add(new Claim(ClaimTypes.GivenName, user.FirstName));
claims.Add(new Claim(ClaimTypes.Surname, user.LastName));
return new ClaimsPrincipal(new ClaimsIdentity(claims, "MyCustom"));
}
private void CreateSession(ClaimsPrincipal transformedPrincipal)
{
var sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
if (FederatedAuthentication.SessionAuthenticationModule != null &&
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies))
{
return;
}
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
//Added line below as per suggestion in one of the posts
//Doesn't seem to have any effect
Thread.CurrentPrincipal = transformedPrincipal;
FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenReceived += SessionAuthenticationModule_SessionSecurityTokenReceived;
}
void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("SessionAuthenticationModule_SessionSecurityTokenReceived");
}
答案 0 :(得分:2)
看起来我必须通过ClaimsIdentity而不是ClaimsPrincipal来访问声明。现在,我可以从我的应用程序中的任何视图或控制器成功访问声明。
((ClaimsIdentity)Thread.CurrentPrincipal.Identity).FindAll(ClaimTypes.Email)
Count = 1
[0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress: me@mydomain.com}
AuthenticationManager中的最终代码库如下所示(请注意,当前线程上的ClaimsPrincipal没有明确的赋值操作。)
public class MyAuthenticationManager : ClaimsAuthenticationManager
{
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (!incomingPrincipal.Identity.IsAuthenticated)
{
return base.Authenticate(resourceName, incomingPrincipal);
}
var transformedPrincipal = this.CreateUserPrincipal(incomingPrincipal.Identity.Name);
this.CreateSession(transformedPrincipal);
return transformedPrincipal;
}
private ClaimsPrincipal CreateUserPrincipal(String userName)
{
List<Claim> claims = new List<Claim>();
var user = SecurityController.GetUserIdentity(userName);
claims.Add(new Claim(ClaimTypes.Name, userName));
claims.Add(new Claim("UserId", user.Id.ToString()));
claims.Add(new Claim(ClaimTypes.Email, user.Email));
claims.Add(new Claim(ClaimTypes.GivenName, user.FirstName));
claims.Add(new Claim(ClaimTypes.Surname, user.LastName));
//claims.Add(new Claim(ClaimTypes.NameIdentifier, userName));
if (user.Account != null)
{
claims.Add(new Claim("AccountId", user.Account.Id.ToString()));
claims.Add(new Claim("AccountName", user.Account.Name.ToString()));
}
if (user.Owner != null)
{
claims.Add(new Claim("OwnerId", user.Owner.Id.ToString()));
claims.Add(new Claim("OwnerName", user.Owner.Name.ToString()));
}
return new ClaimsPrincipal(new ClaimsIdentity(claims, "MyCustom"));
}
private void CreateSession(ClaimsPrincipal transformedPrincipal)
{
if (FederatedAuthentication.SessionAuthenticationModule != null &&
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies))
{
return;
}
var sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
}
}
答案 1 :(得分:0)
我没有看到你将ClaimsPrincipal(转换后)添加回Thread.CurrentPrincipal。请尝试
private void CreateSession(ClaimsPrincipal transformedPrincipal)
{
var sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
if (FederatedAuthentication.SessionAuthenticationModule != null &&
FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies))
{
return;
}
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
//Following is the missing line of code.
Thread.CurrentPrincipal = transformedPrincipal;
}