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

2 回答 2

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

这与您的方法之间的区别在于,仅通过重新调用身份验证过程来处理失败的授权 - 没有例外,没有 500s。

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

于 2012-10-31T13:49:23.903 回答
1

除了转换声明的典型案例外,文档还不清楚如何实现 Authenticate。如果您需要根据声明拒绝用户,则只能靠您自己。

我尝试返回 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。

于 2014-03-16T19:25:20.297 回答