ASP.NET Core での単純な承認

ASP.NET Core での承認は、AuthorizeAttribute とそのさまざまなパラメーターを使用して制御されます。 最も基本的な形式では、コントローラー、アクション、または Razor ページに [Authorize] 属性を適用して、そのコンポーネントへのアクセスを認証済みユーザーに限定します。

次のコードでは、AccountController へのアクセスが認証済みユーザーに限定されます。

[Authorize]
public class AccountController : Controller
{
    public ActionResult Login()
    {
    }

    public ActionResult Logout()
    {
    }
}

コントローラーではなくアクションに承認を適用する場合は、アクション自体に AuthorizeAttribute 属性を適用します。

public class AccountController : Controller
{
   public ActionResult Login()
   {
   }

   [Authorize]
   public ActionResult Logout()
   {
   }
}

これで、認証されたユーザーだけが Logout 関数にアクセスできます。

AllowAnonymous 属性を使用して、認証されていないユーザーによる個々のアクションへのアクセスを許可することもできます。 次に例を示します。

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous]
    public ActionResult Login()
    {
    }

    public ActionResult Logout()
    {
    }
}

これにより、認証済みか、未認証または匿名の状態かに関係なくすべてのユーザーがアクセスできる Login アクションを除き、認証されたユーザーだけが AccountController にアクセスできます。

警告

[AllowAnonymous] を指定すると、承認ステートメントがバイパスされます。 [AllowAnonymous] と任意の [Authorize] 属性を組み合わせた場合、[Authorize] 属性は無視されます。 次の例は、コントローラー レベルで [AllowAnonymous] を適用する場合です:

  • コントローラー上の同じコントローラーまたはアクション・メソッド上の [Authorize] 属性からの許可要件はすべて無視されます。
  • 認証ミドルウェアはショートサーキットされませんが、成功する必要はありません。

次のコードを使用すると、LogoutModelRazor ページへのアクセスが、認証されたユーザーに限定されます。

[Authorize]
public class LogoutModel : PageModel
{
    public async Task OnGetAsync()
    {

    }

    public async Task<IActionResult> OnPostAsync()
    {

    }
}

すべてのユーザーの認証をグローバルに要求する方法の詳細については、「認証されたユーザーを要求する」を参照してください。

属性と Razor ページを承認する

AuthorizeAttribute を Razor ページ ハンドラーに適用することは "できません"。 たとえば、[Authorize] は、OnGetOnPost、または他のページ ハンドラーには適用できません。 ハンドラーごとに異なる承認要件を持つページには、ASP.NET Core MVC コントローラーの使用を検討してください。 さまざまな承認要件が必要な場合に MVC コントローラーを使用することは:

  • 最も複雑でないアプローチです。
  • Microsoft がお勧めするアプローチです。

MVC コントローラーを使用しない場合は、次の 2 つのアプローチを使用して、Razor ページ ハンドラー メソッドに承認を適用できます。

  • 異なる承認を必要とするページ ハンドラーには、個別のページを使用します。 共有コンテンツを 1 つ以上の部分ビューに移動します。 可能であれば、これはお勧めのアプローチです。

  • 共通ページを共有する必要があるコンテンツの場合は、IAsyncPageFilter.OnPageHandlerSelectionAsync の一部として承認を実行するフィルターを記述します。 PageHandlerAuth GitHub プロジェクトでこのアプローチを示します。

    [TypeFilter(typeof(AuthorizeIndexPageHandlerFilter))]
    public class IndexModel : PageModel
    {
        private readonly ILogger<IndexModel> _logger;
    
        public IndexModel(ILogger<IndexModel> logger)
        {
            _logger = logger;
        }
    
        public void OnGet()
        {
    
        }
    
        public void OnPost()
        {
    
        }
    
        [AuthorizePageHandler]
        public void OnPostAuthorized()
        {
    
        }
    }
    
    public class AuthorizeIndexPageHandlerFilter : IAsyncPageFilter, IOrderedFilter
    {
        private readonly IAuthorizationPolicyProvider policyProvider;
        private readonly IPolicyEvaluator policyEvaluator;
    
        public AuthorizeIndexPageHandlerFilter(
            IAuthorizationPolicyProvider policyProvider,
            IPolicyEvaluator policyEvaluator)
        {
            this.policyProvider = policyProvider;
            this.policyEvaluator = policyEvaluator;
        }
    
        // Run late in the selection pipeline
        public int Order => 10000;
    
        public Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) => next();
    
        public async Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
        {
            var attribute = context.HandlerMethod?.MethodInfo?.GetCustomAttribute<AuthorizePageHandlerAttribute>();
            if (attribute is null)
            {
                return;
            }
    
            var policy = await AuthorizationPolicy.CombineAsync(policyProvider, new[] { attribute });
            if (policy is null)
            {
                return;
            }
    
            await AuthorizeAsync(context, policy);
        }
    
        #region AuthZ - do not change
        private async Task AuthorizeAsync(ActionContext actionContext, AuthorizationPolicy policy)
        {
            var httpContext = actionContext.HttpContext;
            var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, httpContext);
            var authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, httpContext, actionContext.ActionDescriptor);
            if (authorizeResult.Challenged)
            {
                if (policy.AuthenticationSchemes.Count > 0)
                {
                    foreach (var scheme in policy.AuthenticationSchemes)
                    {
                        await httpContext.ChallengeAsync(scheme);
                    }
                }
                else
                {
                    await httpContext.ChallengeAsync();
                }
    
                return;
            }
            else if (authorizeResult.Forbidden)
            {
                if (policy.AuthenticationSchemes.Count > 0)
                {
                    foreach (var scheme in policy.AuthenticationSchemes)
                    {
                        await httpContext.ForbidAsync(scheme);
                    }
                }
                else
                {
                    await httpContext.ForbidAsync();
                }
    
                return;
            }
        }
    

警告

PageHandlerAuth サンプル アプローチを使用しても、以下は実行 "されません"。

  • ページ、ページ モデル、またはグローバルに適用される承認属性を使用した構成。 承認属性を構成すると、1 つ以上の AuthorizeAttribute または AuthorizeFilter インスタンスもページに適用した場合に、認証と承認が複数回実行されます。
  • 他の ASP.NET Core 認証および承認システムと連携した作業。 このアプローチの使用がアプリケーションに対して正しく動作することを確認する必要があります。

Razor ページ ハンドラーで AuthorizeAttribute をサポートする予定はありません。