1. ホーム
  2. c#

[解決済み] ASP.NET Core 2.0認証ミドルウェア

2023-01-29 14:58:45

質問

Core 1.1 で @blowdart さんのアドバイスに従い、カスタムミドルウェアを実装しました。

https://stackoverflow.com/a/31465227/29821

このように動作しました。

  1. ミドルウェアが実行されました。リクエストヘッダからトークンを拾いました。
  2. トークンを検証し、有効であれば複数のクレームを含むアイデンティティ(ClaimsIdentity)を構築し、HttpContext.User.AddIdentity()で追加しました。
  3. ConfigureServicesでservices.AddAuthorizationを使って、ミドルウェアが提供するクレームを要求するためのポリシーを追加しています。
  4. コントローラ/アクションでは、[Authorize(Roles = "ミドルウェアが追加した何らかのロール")]を使用することになりますね。

トークンが有効でなく (上記のステップ 2)、クレームが追加されなかった場合、"No authenticationScheme was specified, and there was no DefaultChallengeScheme found." となることを除いて、これは 2.0 である程度動作します。

ということは、2.0でauthが変わったと読み取れます。

https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x

ASP.NET Core 2.0で同じことをするための正しい道は何でしょうか?本当にカスタム認証を行うための例が見当たりません。

どのように解決するのですか?

長い間この問題を解決しようとしてきた結果、Microsoft が core 2.0 の新しい単一ミドルウェア設定のためにカスタム認証ハンドラを作成することをどのように望んでいるかがようやくわかりました。

MSDN のドキュメントに目を通した後、次のようなクラスを見つけました。 AuthenticationHandler<TOption> というクラスがあり、これは IAuthenticationHandler インターフェイスを実装しています。

そこから、既存の認証スキームがあるコードベース全体が https://github.com/aspnet/Security

これらのうちの1つの内部では、MicrosoftがJwtBearer認証スキームをどのように実装しているかが示されています。( https://github.com/aspnet/Security/tree/master/src/Microsoft.AspNetCore.Authentication.JwtBearer )

このコードのほとんどを新しいフォルダにコピーし、そして JwtBearer .

では JwtBearerHandler クラス (これは AuthenticationHandler<> を拡張したもの) のオーバーライドがあります。 Task<AuthenticateResult> HandleAuthenticateAsync()

カスタムトークンサーバを使用してクレームを設定するための古いミドルウェアを追加しましたが、パーミッションに関するいくつかの問題が発生し、単に 200 OK の代わりに 401 Unauthorized の代わりに、トークンが無効でクレームが設定されていない場合に使用します。

をオーバーライドしていたことに気づきました。 Task HandleChallengeAsync(AuthenticationProperties properties) これは、何らかの理由で [Authorize(Roles="")] を介してパーミッションを設定するために使用されます。

このオーバーライドを削除した後、コードは動作し、正常に 401 をスローしていました。

ここから得られる主な情報は、今はカスタムミドルウェアを使うことができないので、それを実装するために AuthenticationHandler<> で実装しなければならず、また DefaultAuthenticateSchemeDefaultChallengeScheme を使用する場合 services.AddAuthentication(...) .

これはすべてどのように見えるかの例です。

Startup.cs / ConfigureServices() に追加します。

services.AddAuthentication(options =>
{
    // the scheme name has to match the value we're going to use in AuthenticationBuilder.AddScheme(...)
    options.DefaultAuthenticateScheme = "Custom Scheme";
    options.DefaultChallengeScheme = "Custom Scheme";
})
.AddCustomAuth(o => { });

Startup.cs / Configure()に追加します。

app.UseAuthentication();

新規ファイルCustomAuthExtensions.csを作成します。

public static class CustomAuthExtensions
{
    public static AuthenticationBuilder AddCustomAuth(this AuthenticationBuilder builder, Action<CustomAuthOptions> configureOptions)
    {
        return builder.AddScheme<CustomAuthOptions, CustomAuthHandler>("Custom Scheme", "Custom Auth", configureOptions);
    }
}

新規ファイル CustomAuthOptions.cs を作成します。

public class CustomAuthOptions: AuthenticationSchemeOptions
{
    public CustomAuthOptions()
    {

    }
}

新規ファイル CustomAuthHandler.cs を作成します。

internal class CustomAuthHandler : AuthenticationHandler<CustomAuthOptions>
{
    public CustomAuthHandler(IOptionsMonitor<CustomAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
    {
        // store custom services here...
    }
    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        // build the claims and put them in "Context"; you need to import the Microsoft.AspNetCore.Authentication package
        return AuthenticateResult.NoResult();
    }
}