1

我有一个 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 以再次进行身份验证。

我错过了什么?

4

1 回答 1

0

在您的 Authenticate 覆盖中,您可能应该通过基本 ClaimsAuthenticationManager 路由incomingPrincipal:

return base.Authenticate(resourceName, incomingPrincipal);
于 2013-07-16T16:02:30.703 回答