2012-10-31 32 views
2

我有一个FubuMvc网站,它使用来自WIF单点登录服务器的基于声明的授权。身份验证发生在SSO上,包括角色和一组自定义声明的声明被传递到网站以进行授权。根据索赔允许或拒绝访问整个站点

SSO和网站正常工作,但基于角色的授权,但我想要做的是拒绝访问整个网站保存错误页面的基础上没有自定义声明。目前我正在使用自定义ClaimsAuthenticationManager,它检查索赔并检查是否存在所需索赔。如果声明丢失,则会引发异常。这会导致500错误,但我真正想要的是系统抛出401错误并重定向到网站上的未授权页面。

以下是自定义ClaimsAuthenticationManager的示例。

public class CustomAuthenticationManager : ClaimsAuthenticationManager 
{ 
    private readonly string expectedClaim; 

    public CustomAuthenticationManager (object config) 
    { 
     var nodes = config as XmlNodeList; 
     foreach (XmlNode node in nodes) 
     { 
      using (var stringReader = new StringReader(node.OuterXml)) 
      using (var rdr = new XmlTextReader(stringReader)) 
      { 
       rdr.MoveToContent(); 
       rdr.Read(); 
       string claimType = rdr.GetAttribute("claimType"); 
       if (claimType.CompareTo(ClaimTypes.CustomClaim) != 0) 
       { 
        throw new NotSupportedException("Only custom claims are supported"); 
       } 
       expectedSystemName = rdr.GetAttribute("customClaimValue"); 
      } 
     } 
    } 

    public override IClaimsPrincipal Authenticate(
     string resourceName, IClaimsPrincipal incomingPrincipal) 
    { 
     var authenticatedIdentities = incomingPrincipal.Identities.Where(x => x.IsAuthenticated); 
     if (authenticatedIdentities.Any() && 
       authenticatedIdentities.Where(x => x.IsAuthenticated) 
             .SelectMany(x => x.Claims) 
             .Where(x => x.ClaimType == ClaimTypes.CustomClaim) 
             .All(x => x.Value != expectedClaim)) 
     { 
       throw new HttpException(
        (int)HttpStatusCode.Unauthorized, 
        "User does not have access to the system"); 
     } 
     return base.Authenticate(resourceName, incomingPrincipal); 
    } 
} 

上述工作,并阻止对系统的访问,但TI并不十分友好的使用,因为用户只是得到一个500错误。此外,因为用户基本上登录了他们但没有访问权限,他们无法注销。我公开了一个未经授权的错误页面,该页面提供对匿名用户的访问,但我无法重定向用户。

回答

4

我想知道为什么你在认证管理器中实现了你的逻辑。

你有没有考虑切换到ClaimsAuthorizationManager?对于这个工作,你需要将ClaimsAuthorizationModule添加到您的管道:

<system.webServer> 
    <modules> 
     ... 
     <add name="SessionAuthenticationModule" .... 
     <add name="ClaimsAuthorizationModule" type="Microsoft.IndentityModel.Web.ClaimsAuthorizationModule, Microsoft.IndentityModel.Web" /> 
    </modules> 
</system.webServer> 

然后创建您的授权角色的结构:

<claimsAuthorizationManager type="yourtype, yourassembly"> 
     <requiredClaim claimType="foobar" /> 
</claimsAuthorizationManager> 

,并在经理:

public class FederatedClaimsAuthorizationManager : ClaimsAuthorizationManager 
{ 
    private List<string> _requiredClaims = new List<string>(); 

    public FederatedClaimsAuthorizationManager(object config) 
    { 
     XmlNodeList nodes = config as XmlNodeList; 
     foreach (XmlNode node in nodes) 
     { 
      XmlTextReader xtr = new XmlTextReader(new StringReader(node.OuterXml)); 
      xtr.MoveToContent(); 

      _requiredClaims.Add(xtr.GetAttribute("claimType")); 
     } 
    } 

    public override bool CheckAccess(AuthorizationContext context) 
    { 
     IClaimsIdentity identity = context.Principal.Identities[0]; 

     return !identity.IsAuthenticated || 
       identity.Claims.Any(c => _requiredClaims.Any(rq => c.ClaimType == rq)); 
    } 
} 

这与你的方法之间的区别在于,失败的授权是通过重新激活验证过程来处理的 - 没有例外,没有500秒。

例如 - 如果您在登录页面上使用<wif:FederatedPassiveSignIn />,那么失败的授权只是将用户重定向到登录页面,您可以检查用户是否已通过身份验证,并显示“您已被重定向到登录页面可能意味着您试图访问您无权访问的资源“。

+0

我已经验证过该答案是正确的。授权必须在'ClaimsAuthorizationManager'中完成。从'CheckAccess'返回'false'是获得401响应的唯一方法。 –

1

除了转换声明的典型情况之外,文档不清楚如何实现身份验证。如果您需要根据索赔拒绝用户,那么您就是您自己的。

我已经尝试返回null并抛出各种异常,包括401(类似于你的例子)。我发现最好的解决方案是创建并返回一个匿名主体。

using System.Security.Principal; 

... 

public class CustomAuthenticationManager : ClaimsAuthenticationManager 
{ 
    public override IClaimsPrincipal Authenticate(
     string resourceName, 
     IClaimsPrincipal incomingPrincipal) 
    { 
     ... 

     ClaimsIdentity identity = new GenericIdentity(String.Empty); 
     return new GenericPrincipal(identity, new string[0] { }); 
    } 
} 

您必须传递一个空字符串作为标识名,以便对通用声明标识上的IsAuthenticated返回false。

相关问题