2

WIFシングルサインオンサーバーからのクレームベースの承認を使用するFubuMvcWebサイトがあります。認証はSSOで行われ、役割と一連のカスタムクレームを含むクレームが承認のためにWebサイトに渡されます。

SSOとWebサイトは、役割ベースの承認と同様に正常に機能しますが、私がやりたいのは、カスタムクレームがないことに基づいて、サイト全体へのアクセスを拒否してエラーページを保存することです。ClaimsAuthenticationManager現在、クレームを検査し、必要なクレームの存在をチェックするカスタムを使用しています。クレームが欠落している場合は、例外がスローされます。これにより500エラーが発生しますが、私が本当に望んでいるのは、システムが401エラーをスローし、Webサイトの許可されていないページにリダイレクトすることです。

以下は、カスタムの例です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);
    }
}

上記は機能し、システムへのアクセスを妨げますが、ユーザーが500エラーを受け取るだけなので、tiはあまり使い勝手が良くありません。また、ユーザーは基本的にログインしていますが、アクセス権がないため、ログアウトする方法がありません。匿名ユーザーへのアクセスを提供する不正なエラーページを公開しましたが、ユーザーをリダイレクトする方法はまだありません。

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

これとあなたのアプローチの違いは、失敗した承認は認証プロセスを再起動するだけで処理されるということです-例外はなく、500もありません。

たとえば<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] { });
    }
}

ジェネリッククレームIDのIsAuthenticatedがfalseを返すには、ID名として空の文字列を渡す必要があります。

于 2014-03-16T19:25:20.297 に答える