ClaimsPrincipal没有得到妥善保存

时间:2013-07-15 18:50:36

标签: authentication asp.net-mvc-4 forms-authentication claims-based-identity claims

我有一个ASP.NET MVC 4应用程序,我正在尝试实现基于声明的身份验证和授权。我们有一个SSO代理,在标头中插入有关用户的某些信息(例如用户名)。我已经实现了自己的ClaimsAuthenticationManager,我想要做的是从头文件中获取用户名,创建一个包含UserName声明的ClaimsPrinsipal,将其传递给我的ClaimsAuthenticationManager,它将命中数据库以确定用户应该拥有的角色,并使用角色声明填充主体。然后我想在用户会话的其余部分使用转换后的声明。

到目前为止我所拥有的:

的Web.config:

<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;
    }
}

的Global.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检查声明时,它们都不存在(同样,Principal不再经过身份验证)。它只是重新指向AccountController再次进行身份验证。

我错过了什么?

1 个答案:

答案 0 :(得分:0)

在Authenticate覆盖中,您应该将incomingPrincipal路由到基础ClaimsAuthenticationManager:

return base.Authenticate(resourceName, incomingPrincipal);