我有一个 ASP.NET MVC 4 应用程序,我试图在其中实现基于声明的身份验证和授权。我们有一个 SSO 代理,它在标头中插入有关用户的某些信息(例如用户名)。我已经实现了自己的 ClaimsAuthenticationManager,我想要做的是从标题中获取用户名,创建一个包含 UserName 声明的 ClaimsPrinsipal,将其传递给我的 ClaimsAuthenticationManager,它将访问数据库以确定用户应该拥有的角色,并用角色声明填充主体。然后我想在用户会话的其余部分使用转换后的声明。
到目前为止我所拥有的:
网络配置:
<configuration> ... <system.web> ... <authentication mode="Forms"> <forms loginUrl="~/Account/Authorize" timeout="20" /> </authentication> </system.web> </configuration>
MyClaimsTransformer.cs
public class MyClaimsTransformer : ClaimsAuthenticationManager
{
private readonly IAuthenticationUow _authenticationUow;
private readonly IWebServiceUrls _webServiceUrls;
public MyClaimsTransformer(IAuthenticationUow authenticationUow, IWebServiceUrls webServiceUrls)
{
_authenticationUow = authenticationUow;
_webServiceUrls = webServiceUrls;
}
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal == null || incomingPrincipal.Identity == null || !incomingPrincipal.Identity.IsAuthenticated)
throw new SecurityException("No claims principal or not authenticated");
var userName = incomingPrincipal.Identity.Name;
if (string.IsNullOrWhiteSpace(userName))
throw new SecurityException("No user name found");
// Add role claims
return incomingPrincipal;
}
}
全球.asax.cs
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
FederatedAuthentication.FederationConfigurationCreated += FederatedAuthentication_FederationConfigurationCreated;
}
private void FederatedAuthentication_FederationConfigurationCreated(object sender, System.IdentityModel.Services.Configuration.FederationConfigurationCreatedEventArgs e)
{
WebServiceUrls serviceUrls = new WebServiceUrls();
AppProperties appProperties = new AppProperties();
serviceUrls.UserNameWebServiceUrl = appProperties.UserNameWebServiceUrl;
serviceUrls.PointOfContactWebServiceUrl = appProperties.PointOfContactWebServiceUrl;
e.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager =
ObjectFactory.With<IWebServiceUrls>(serviceUrls).GetInstance<MyClaimsTransformer>();
}
}
AccountController.cs
[Authorize]
public class AccountController : BaseController
{
[AllowAnonymous]
public ActionResult Authorize(string returnUrl)
{
string userId = Request.Headers["userid"];
if (Url.IsLocalUrl(returnUrl))
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, userId)
};
var id = new ClaimsIdentity(claims, "Custom", ClaimTypes.Name, ClaimTypes.Role);
var principal = new ClaimsPrincipal(id);
// call out to registered ClaimsAuthenticationManager
var claimsAuthManager = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager;
// set the transformed principal
var url = Request.Url;
if (url != null)
{
var newPrincipal = claimsAuthManager.Authenticate(url.AbsolutePath, principal);
SetSessionCookie(newPrincipal);
Thread.CurrentPrincipal = newPrincipal;
}
return Redirect(returnUrl);
}
throw new InvalidDataException("BAD URL");
}
private void SetSessionCookie(ClaimsPrincipal incomingPrincipal)
{
SessionSecurityToken token = new SessionSecurityToken(incomingPrincipal);
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(token);
}
}
这段代码运行良好,当该Thread.CurrentPrincipal = newPrincipal;
行被执行时,所有正确的声明都在主体中。但是当我使用我的自定义 ClaimsAuthorizationManager 来检查声明时,它们都不存在(而且,主体不再经过身份验证)。它只是重新定向回 AccountController 以再次进行身份验证。
我错过了什么?