複数のJWTベアラー認証を使用する


89

ASP.NET Core 2で複数のJWTトークン発行者をサポートすることは可能ですか?外部サービス用のAPIを提供したいので、JWTトークンの2つのソース(FirebaseとカスタムJWTトークン発行者)を使用する必要があります。ASP.NETコアでは、Bearer認証スキームにJWT認証を設定できますが、1つの機関にのみ設定できます。

  services
        .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.Authority = "https://securetoken.google.com/my-firebase-project"
            options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidIssuer = "my-firebase-project"
                    ValidateAudience = true,
                    ValidAudience = "my-firebase-project"
                    ValidateLifetime = true
                };
        }

複数の発行者とオーディエンスを持つことができますが、複数の機関を設定することはできません。


1
AFAIKでは、JWTに任意の数のプロパティを追加できます。したがって、JWTに2つの発行者名を記録することを妨げるものは何もありません。問題は、各発行者が異なるキーを使用して署名している場合、アプリケーションが両方のキーを認識する必要があるということです。
Tim Biegeleisen 2018

回答:


196

あなたは完全にあなたが望むものを達成することができます:

services
    .AddAuthentication()
    .AddJwtBearer("Firebase", options =>
    {
        options.Authority = "https://securetoken.google.com/my-firebase-project"
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = "my-firebase-project"
            ValidateAudience = true,
            ValidAudience = "my-firebase-project"
            ValidateLifetime = true
        };
    })
    .AddJwtBearer("Custom", options =>
    {
        // Configuration for your custom
        // JWT tokens here
    });

services
    .AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .AddAuthenticationSchemes("Firebase", "Custom")
            .Build();
    });

コードとそのコードの違いを見てみましょう。

AddAuthentication パラメータはありません

デフォルトの認証スキームを設定すると、すべてのリクエストで、認証ミドルウェアはデフォルトの認証スキームに関連付けられた認証ハンドラーを実行しようとします。現在、2つの可能な認証スキームがあるため、そのうちの1つを実行しても意味がありません。

別の過負荷を使用する AddJwtBearer

AddXXX認証を追加するすべての方法には、いくつかの過負荷があります。

ここで、同じ認証方法を2回使用しますが、認証スキームは一意である必要があるため、2番目のオーバーロードを使用する必要があります。

デフォルトのポリシーを更新する

リクエストは自動的に認証されなくなるため、[Authorize]一部のアクションに属性を設定すると、リクエストが拒否され、HTTP 401が発行されます。

認証ハンドラーに要求を認証する機会を与えたいので、それは私たちが望んでいることではないのでFirebaseCustom認証スキームと認証スキームの両方が要求を認証するように試みられるべきであることを示すことによって、承認システムのデフォルトポリシーを変更します。

それはあなたがいくつかの行動をより制限することを妨げるものではありません。[Authorize]属性がありAuthenticationSchemesますが、制度が有効である認証上書きすることを可能にするプロパティを。

より複雑なシナリオがある場合は、ポリシーベースの承認を利用できます。公式ドキュメントは素晴らしいと思います。

一部のアクションはFirebaseによって発行されたJWTトークンでのみ使用可能であり、特定の値を持つクレームが必要であると想像してみてください。あなたはこのようにそれを行うことができます:

// Authentication code omitted for brevity

services
    .AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .AddAuthenticationSchemes("Firebase", "Custom")
            .Build();

        options.AddPolicy("FirebaseAdministrators", new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .AddAuthenticationSchemes("Firebase")
            .RequireClaim("role", "admin")
            .Build());
    });

その後[Authorize(Policy = "FirebaseAdministrators")]、いくつかのアクションで使用できます。

注意すべき最後のポイント:AuthenticationFailedイベントをキャッチして最初のAddJwtBearerポリシー以外のものを使用している場合、IDX10501: Signature validation failed. Unable to match key...これはシステムAddJwtBearerが一致するまで順番にチェックすることが原因であることがわかります。通常、エラーは無視できます。


4
これには、ヘッダー値をFirebaseまたはカスタムソリューションから変更する必要がありますか?すなわち。その代わりにAuthorization : Bearer <token>、ヘッダーAuthorization : Firebase <token>は例えばですか?この解決策を試したところ、「スキーム「ベアラー」に認証ハンドラーが登録されていません」というエラーが発生しました。
ラッシュフリスビー2018

4
いいえ、ヘッダーを変更する必要はありません。エラーメッセージは、存在しない認証スキーム(ベアラー)を参照していることを示しています。この例では、登録されている2つのスキームはFirebaseとCustomであり、これらは.AddJwtBearerメソッド呼び出しの最初の引数です。
ミカエルDerriey

6
こんにちは。このソリューションだけを探していました。残念ながら、「authenticationSchemeが指定されておらず、DefaultChallengeSchemeが見つかりませんでした」という例外が発生します。options.DefaultPolicyは正常に設定されています。何か案は?
terjetyl

13
これは非常に有益な答えであり、私が見たものの多くをあちこちでばらばらにまとめました。
アロンW.

2
@TylerOhlsenそれは正しくありません。あなたが説明する場合に使用されますが、それだけではありません。エンドポイントレベルで承認要件を指定しないが、MVCコントローラーやアクションを空の[Authorize]属性で装飾する場合にも使用されます。
ミカエルDerriey

5

これはMickaëlDerrieyの答えの延長です。

私たちのアプリには、内部ソースから解決するカスタム認証要件があります。Auth0を使用していましたが、OpenIDを使用したMicrosoftアカウント認証に切り替えています。これは、ASP.Net Core2.1スタートアップから少し編集されたコードです。将来の読者のために、これは指定されたバージョンに対してこの記事の執筆時点で機能します。呼び出し元は、ベアラートークンとして渡された着信リクエストでOpenIDのid_tokenを使用します。この質問と回答が私を助けたのと同じくらい、他の誰かがID権限の変換を行おうとするのに役立つことを願っています。

const string Auth0 = nameof(Auth0);
const string MsaOpenId = nameof(MsaOpenId);

string domain = "https://myAuth0App.auth0.com/";
services.AddAuthentication()
        .AddJwtBearer(Auth0, options =>
            {
                options.Authority = domain;
                options.Audience = "https://myAuth0Audience.com";
            })
        .AddJwtBearer(MsaOpenId, options =>
            {
                options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateAudience = true,
                    ValidAudience = "00000000-0000-0000-0000-000000000000",

                    ValidateIssuer = true,
                    ValidIssuer = "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0",

                    ValidateIssuerSigningKey = true,
                    RequireExpirationTime = true,
                    ValidateLifetime = true,
                    RequireSignedTokens = true,
                    ClockSkew = TimeSpan.FromMinutes(10),
                };
                options.MetadataAddress = "https://login.microsoftonline.com/9188040d-6c67-4c5b-b112-36a304b66dad/v2.0/.well-known/openid-configuration";
            }
        );

services.AddAuthorization(options =>
{
    options.DefaultPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .AddAuthenticationSchemes( Auth0, MsaOpenId )
        .Build();

    var approvedPolicyBuilder =  new AuthorizationPolicyBuilder()
           .RequireAuthenticatedUser()
           .AddAuthenticationSchemes(Auth0, MsaOpenId)
           ;

    approvedPolicyBuilder.Requirements.Add(new HasApprovedRequirement(domain));

    options.AddPolicy("approved", approvedPolicyBuilder.Build());
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.