web-dev-qa-db-ja.com

アクション名に応じたユーザーの承認

私は多くのアクションを持つ多くのコントローラーを持っています。各アクションには独自のロールがあります(ロール名= ControllerName.actionName)。

以前のバージョンでは、現在のユーザーが "汎用" AuthorizeAttributeを使用してアクションにアクセスできるかどうかをテストできました。

public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
    string currentAction = actionContext.ActionDescriptor.ActionName;
    string currentController = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
    Roles = (currentController + "." + currentAction).ToLower();
    base.OnAuthorization(actionContext);
}

バージョンasp.net 5では、要件を使用する必要があることがわかりました( ASP.NET CoreでカスタムAuthorizeAttributeをどのように作成しますか? )。問題は、AuthorizationContextが、ユーザーが到達しようとしているアクションに関する情報を提供しないことです。

各アクションにAuthorize属性を設定したくないのですが、新しいフレームワークで要件を達成する方法はありますか? (私はHttpContext.Currentの使用を避けたい、パイプラインアーキテクチャにうまく適合しない)

22
yeska

カスタム認証を適用する一般的なプロセスは次のとおりです。あなたを飾る役割のクレームを追加できるので、あなたの状況はステップ1で完全に解決できるかもしれません。

1。authenticateユーザーのIDを作成して

ミドルウェアを作成し、それを_IApplicationBuilder.UseMiddleware<>_を介してパイプラインに挿入すると、カスタム認証が行われます。ここで、後で承認に必要な情報を抽出し、ClaimsIdentityに入れます。ここにHttpContextがあるので、ヘッダー、Cookie、要求されたパスなどから情報を取得できます。次に例を示します。

_public class MyAuthHandler : AuthenticationHandler<MyAuthOptions>
{
   protected override Task<AuthenticationTicket> HandleAuthenticateAsync()
   {
      // grab stuff from the HttpContext
      string authHeader = Request.Headers["Authorization"] ?? "";
      string path = Request.Path.ToString() ?? "";

      // make a MyAuth identity with claims specifying what we'll validate against
      var identity = new ClaimsIdentity(new[] {
         new Claim(ClaimTypes.Authentication, authHeader),
         new Claim(ClaimTypes.Uri, path)
      }, Options.AuthenticationScheme);

      var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), 
         new AuthenticationProperties(), Options.AuthenticationScheme);
      return Task.FromResult(ticket);
   }
}

public class MyAuthOptions : AuthenticationOptions
{
   public const string Scheme = "MyAuth";
   public MyAuthOptions()
   {
      AuthenticationScheme = Scheme;
      AutomaticAuthentication = true;
   }
}

public class MyAuthMiddleware : AuthenticationMiddleware<MyAuthOptions>
{
   public MyAuthMiddleware(
               RequestDelegate next,
               IDataProtectionProvider dataProtectionProvider,
               ILoggerFactory loggerFactory,
               IUrlEncoder urlEncoder,
               IOptions<MyAuthOptions> options,
               ConfigureOptions<MyAuthOptions> configureOptions)
         : base(next, options, loggerFactory, urlEncoder, configureOptions)
   {
   }

   protected override AuthenticationHandler<MyAuthOptions> CreateHandler()
   {
      return new MyAuthHandler();
   }
}

public static class MyAuthMiddlewareAppBuilderExtensions
{
   public static IApplicationBuilder UseMyAuthAuthentication(this IApplicationBuilder app, string optionsName = "")
   {
      return app.UseMiddleware<MyAuthMiddleware>(
         new ConfigureOptions<MyAuthOptions>(o => new MyAuthOptions()) { Name = optionsName });
   }
}
_

このミドルウェアを使用するには、ルーティングの前にこれを_Startup.Configure_に挿入します:app.UseMyAuthAuthentication();

2。authorizeアイデンティティに要件を適用する

ユーザーのIDを作成しましたが、それを適用する必要があります。これを行うには、次のようにAuthorizationHandlerを記述する必要があります。

_  public class MyAuthRequirement : AuthorizationHandler<MyAuthRequirement>, IAuthorizationRequirement
  {
     public override void Handle(AuthorizationContext context, MyAuthRequirement requirement)
     {
        // grab the identity for the MyAuth authentication
        var myAuthIdentities = context.User.Identities
           .Where(x => x.AuthenticationType == MyAuthOptions.Scheme).FirstOrDefault();
        if (myAuthIdentities == null)
        {
           context.Fail();
           return;
        }

        // grab the authentication header and uri types for our identity
        var authHeaderClaim = myAuthIdentities.Claims.Where(x => x.Type == ClaimTypes.Authentication).FirstOrDefault();
        var uriClaim = context.User.Claims.Where(x => x.Type == ClaimTypes.Uri).FirstOrDefault();
        if (uriClaim == null || authHeaderClaim == null)
        {
           context.Fail();
           return;
        }

        // enforce our requirement (evaluate values from the identity/claims)
        if ( /* passes our enforcement test */ )
        {
           context.Succeed(requirement);
        }
        else
        {
           context.Fail();
        }
     }
  }
_

。許可ハンドラとして要件ハンドラを追加

認証要件を_Startup.ConfigureServices_に追加して、使用できるようにする必要があります。

_// add our policy to the authorization configuration
services.ConfigureAuthorization(auth =>
{
   auth.AddPolicy(MyAuthOptions.Scheme, 
      policy => policy.Requirements.Add(new MyAuthRequirement()));
});
_

4。認証ポリシーを使用します

最後のステップは、[Authorize("MyAuth")]でアクションまたはコントローラーを装飾することにより、特定のアクションにこの要件を適用することです。多数のコントローラーがあり、それぞれに適用が必要な多くのアクションがある場合、基本クラスを作成し、その単一のコントローラーを装飾することができます。

より簡単な状況:

各アクションには独自のロールがあります(ロール名= ControllerName.actionName>)

[Authorize(Roles = "controllername.actionname")]ですべてのアクションをすでに微調整している場合は、おそらく上記のパート1だけが必要です。特定のリクエストに有効な新しいClaim(ClaimTypes.Role, "controllername.actionname")を追加するだけです。

49
jltrem