ASP.NET Core Identity実戦(4)ライセンスプロセス


皆さん、こんにちは、私はrocket robinです.この文章は一緒にAspを勉強します.Net Coreのライセンスプロセス

前情提要


以前の記事では、認証と認可は2つの別々のプロセスであり、認証プロセスはIdentityに属していないと述べています.同じライセンス・プロシージャもIdentityではありません.ライセンス・プロシージャがIdentityシリーズに配置されている理由は、認証プロシージャと同じです.メンバー・システムと一緒に配置すると分かりやすいです.

手がける


ライセンスプロセスがどこで発生しているかを明らかにする前に、ポリシーのライセンスを知っていれば、このセクションをすばやく参照することができます.
以前に作成したアイテムを開き、Demoというコントローラを追加します.コントローラコードは次のとおりです.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace IdentityDemo.Controllers
{
    [Produces("application/json")]
    [Route("api/demo")]
    public class DemoController : Controller
    {
        [Authorize]
        [HttpGet]
        public object Get()
        {
            return new
            {
                User.Identity.Name,
                User.Identity.IsAuthenticated
                 ...
          

前に登録したアカウントでシステムにログインし、/api/demoにアクセスすると、次の結果が得られます.
{
    "name": "[email protected]",
    "isAuthenticated": true
}

次にログインを終了し、/api/demoに再アクセスすると、ログインページにジャンプします.このプロセスでAuthorizeのプロパティが重要な役割を果たします.次に、Authorizeプロパティを削除し、前の2つの操作を繰り返します.ログインしていない結果は次のとおりです.
{
    "name": null,
    "isAuthenticated": false
}

この2つの小さな例から,Authorizeプロパティがログインしていないユーザをブロックしているなど,Authorizeプロパティが要求をブロックしていると容易に推測できるだろうか.

認証プロセスの発生地


Authorizeプロパティがリクエストをブロックしたのではなく、このメソッドにアクセスするために許可される必要があることをマークしただけで、本当にリクエストをブロックしたのは「Mvcミドルウェア」です.ActionはMvcによって実行され、Mvcが実行されるとActionのAuthorizeプロパティが確認され、ライセンス操作を行うかどうか(成功したライセンスはアクセスでき、失敗したらブロックされる(例えばログインにジャンプする)、およびどのようにライセンスするか(動物園の例では、2番目の警備員は確実な状況に応じて決定される)、すなわちカスタムライセンス(ロールなど)が決定されます.
また、アクションメソッドに[Authorize]のタグを付けるだけであれば、IsAuthenticatedがtrueであるかどうか、すなわち認証フェーズ(Authenticationミドルウェア)が認証に合格したかどうかを検証するのがデフォルトの動作です.
今、私たちは2つの点を知っています.
  • 認証プロセスAuthenticationは、Authenticationミドルウェアの
  • で発生する.
  • 承認プロセスAuthorizationは、Mvcミドルウェアの
  • で発生する.

    ポリシー・ベースの柔軟なライセンス


    企業アプリケーションで最も一般的なのは、ロールベースのライセンスです.ロールのライセンスを実現する方法は2つあります.1つは、Authorizeの特性に直接書かれています.
    [Authorize(Roles = "admin,super-admin,")]
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task Test()
    
    

    ただし、この方法は推奨されません.これでは、「ロール」と「Uri」のバインドを「コードにハードコーディングされています」とします.多くのシーンでは適切ではありません.これから説明するポリシーベースのライセンスでは、ライセンスロジックをカスタマイズできます.これにより、柔軟性が向上します.

    ポリシー・ポリシー・ベースの認可


    デルのライセンスルールは、ユーザーがロール「admin」またはロール「super-admin」を持つという、上のコードクリップと同じ効果を達成することを要求していると仮定し、この目標を徐々に実現します.

    まず、DIに必要なpolicyを登録します。

    services.AddAuthorization(options =>
    {
        options.AddPolicy("role-policy", policy =>
        {
            policy.AddRequirements(new RoleRequirement("admin","super-admin"));
        });
    });
    

    ポリシーの名前role-policyを指定し、このポリシーの要件を指定しました.要件は主にポリシーの初期値を設定するためです.ポリシー登録時に要件を変更して、権限を柔軟に制御できます.
    次にRoleRequirementを作成します
    public class RoleRequirement : IAuthorizationRequirement
    {
        public IEnumerable Roles { get;   }
        public RoleRequirement(params string[] roles)
        {
            Roles = roles ?? throw new ArgumentNullException(nameof(roles));
             ...
    

    では、私たちのRoleRequirementの主な機能は、含まれるロールを決定することです.含まれるロールはコンストラクション関数で決定されるので、ロール認可の論理(後述するHandler)と具体的な認可のデータを分離します.
    次に、RoleRequirementに対応するプロセッサを実装します.
    public class RoleHandler : AuthorizationHandler
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
        {
    
            foreach (var item in requirement.Roles)
            {
                if (context.User.IsInRole(item))
                {
                    context.Succeed(requirement);
                    return Task.CompletedTask;
                }
            }
            context.Fail();
            return Task.CompletedTask;
             ...
    

    このプロセッサの動作は、現在のユーザがRoleRequirementによって指定された任意のロールにいるかどうかを検証することです.ここで、context.Succeed(requirement);は認証に成功したことを示し、認証に失敗した場合、 context.Fail();を呼び出す必要はありません.この例では、 context.Fail();を呼び出すと、認証に失敗することを保証できます.RoleRequirementのプロセッサは1つしかないので、これは問題ありません.
    前述したように、ロール認可の論理(後述するHandler)と特定の認可のデータを分離しています.RoleHandlerはユーザーにどのような役割があるか分からないため、RoleHandlerはユーザーがどのような役割を持っているかを検証する方法しか知らないが、具体的にユーザーがどのような役割を持っているかは、RoleRequirement によって決定され、これは注目点の分離と単一の職責という2つのプログラミング概念に合致している.
    それから、さっき書いたRoleHandlerをDiに登録します.
    services.AddSingleton();
    

    最後に、元のAttributeを交換します.
    // [Authorize(Roles = "admin,super-admin,")]
    [Authorize(Policy ="role-policy")]
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task Test()
    

    これで、最も基本的なポリシーベースのライセンスが完了します.
    本明細書の例は簡単であり、すべてのライセンス特性を使用していないため、より詳細な使用方法の参考資料が多く、本稿ではあまり紹介しません.また、ASPを参考にすることができます.NET Coreでは、ポリシーに基づいたライセンスにより、ポリシーのライセンスに関する内容を学習します.

    認証時にAuthenticationSchemeを指定する


    AuthenticationSchemeを指定するコードは、次のようになります.
    // [Authorize(Roles = "admin,super-admin,")]
    [Authorize(AuthenticationSchemes ="jwt"/*  ,           AuthenticationHandler    */, Policy ="role-policy")]     [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task Test()
    
    

    前ブログでASP.NET Core Identity実戦(3)認証の過程で、Authenticationミドルウェアには複数のHandlerを配置することができ、1つはデフォルトでアクティブ化されているが、残りはパッシブ呼び出しであり、現在、Authorize特性の中で1つのHandlerを選択して実行している.例えば、Authenticationミドルウェアに2つのHandler--CookieAuthenticationHandlerとJwtAuthenticationHandlerを配置し、CookieAuthenticationHandlerによってデフォルトとして指定されていますが、Jwt認証を経由する場合はどうすればいいですか?
    ここで重要な問題は、HttpContextがAuthenticationミドルウェアを通過した後にMvcミドルウェアに到着し、MvcがActionで指定されたAuthenticationHandlerを確認したときに、Authenticationプロセスが終了したことである.
    どうやってやったの?
    また、HttpContextにはAuthenticateAsyncという拡張メソッドがあり、HttpContextの拡張メソッドとしては、いつでも認証操作を呼び出すことができることを意味します.
    namespace Microsoft.AspNetCore.Authentication
    {
        public static class AuthenticationHttpContextExtensions
        {
            public static Task AuthenticateAsync(this HttpContext context);
            public static Task AuthenticateAsync(this HttpContext context, string scheme);
             ...
         
    

    2番目のリロードを見ると、AuthenticationSchemeの名前が指定されているので、MvcミドルウェアがAttributeがAuthenticationSchemeを指定したことを検出すると、指定されたAuthenticationHandlerを再選択して要求を認証します.

    ライセンスの発生地-AuthorizationFilter


    古いAspでNet時代、私たちはMvcFilterというものを知っています.今も残っています.もしあなたがそれを知らないなら、少し理解することをお勧めします.公式ドキュメントを参照することをお勧めします.
    このセクションのタイトルのように、ライセンスはMicrosoft.AspNetCore.Mvc.Authorization.AuthorizationFilterで発生します.ライセンスのロジックは似ています.

    先に認証を行います


    schemeが指定されている場合は、再認証、ない場合は、前のAuthenticationミドルウェアのライセンス結果を使用します.
        public virtual async Task Microsoft.AspNetCore.Authorization.Policy.PolicyEvaluator.AuthenticateAsync(AuthorizationPolicy policy, HttpContext context)
        {
            if (policy.AuthenticationSchemes != null && policy.AuthenticationSchemes.Count > 0)
            {
                ClaimsPrincipal newPrincipal = null;
                foreach (var scheme in policy.AuthenticationSchemes)
                {
                    var result = await context.AuthenticateAsync(scheme);
                    if (result != null && result.Succeeded)
                    {
                        newPrincipal = SecurityHelper.MergeUserPrincipal(newPrincipal, result.Principal);
                    }
                }
    
                if (newPrincipal != null)
                {
                    context.User = newPrincipal;
                    return AuthenticateResult.Success(new AuthenticationTicket(newPrincipal, string.Join(";", policy.AuthenticationSchemes)));
                }
                else
                {
                    context.User = new ClaimsPrincipal(new ClaimsIdentity());
                    return AuthenticateResult.NoResult();
                }
            }
    
            return (context.User?.Identity?.IsAuthenticated ?? false) 
                ? AuthenticateResult.Success(new AuthenticationTicket(context.User, "context.User"))
                : AuthenticateResult.NoResult();
        }
    

    この中で再び深く検討する価値があるのはcontext.AuthenticateAsync(scheme)で、これはHttpAbstractionsプロジェクトにおける拡張方法であり、その実現は:
        public static Task AuthenticateAsync(this HttpContext context, string scheme) =>
            context.RequestServices.GetRequiredService().AuthenticateAsync(context, scheme);
    
    IAuthenticationService Authenticationミドルウェアでも見たことがありますが、AuthenticationミドルウェアもIAuthenticationServiceを使用しています.前の記事で述べたように、アイデンティティ認証ミドルウェアはパイプでの認証を担当していますが、認証自体はアイデンティティ認証ミドルウェアに縛られているわけではありません.前のブログASP.NET Core Identity実戦(3)認証プロセスの最後に認証されたソースコード

    再承認


    ライセンスは合計3ステップに分かれています
  • IAuthorizeHandlerの例(前に1つ書いた)(1つ以上かもしれない)
  • を入手
  • 実行許可(Handlerごとに許可)
  • がなくなった
  • このコードは簡単です.
        public async Task AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable requirements)
        {
            //    
            var authContext = _contextFactory.CreateContext(requirements, user, resource);
            var handlers = await _handlers.GetHandlersAsync(authContext);
            //    
            foreach (var handler in handlers)
            {
                await handler.HandleAsync(authContext);
                if (!_options.InvokeHandlersAfterFailure && authContext.HasFailed)
                {
                    break;
                }
            }
    
            //   (           )
            var result = _evaluator.Evaluate(authContext);
            if (result.Succeeded)
            {
                _logger.UserAuthorizationSucceeded(GetUserNameForLogging(user));
            }
            else
            {
                _logger.UserAuthorizationFailed(GetUserNameForLogging(user));
            }
            return result;
        }
    

    ここで我々がプロジェクトに書いたコードと関係があるのはIAuthorizeHandlerの例であり,本稿ではRoleHandlerを書いた.
    これで授権プロセスは終わり、授権後にどのように操作するかなどの知識点があります.これらは難しくありません.