ASP.NET Core 中的簡單授權

ASP.NET Core 中的授權是由 AuthorizeAttribute 及其各種參數所控制。 以最基本的形式,將 [Authorize] 屬性套用至控制器、動作或 Razor Page,即可限制只有已驗證的使用者能存取該元件。

下列程式碼會限制只有已驗證使用者能存取 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()
    {
    }
}

只有已驗證的使用者允許存取 AccountController,但 Login 動作除外,無論已驗證或未經驗證 / 匿名狀態為何,每個人都可以存取此動作。

警告

[AllowAnonymous] 略過授權陳述式。 如果您結合 [AllowAnonymous][Authorize] 屬性,則會略過 [Authorize] 屬性。 例如,如果您在控制器層級套用 [AllowAnonymous]

  • 系統會忽略來自相同控制器上 [Authorize] 屬性或控制器上動作方法的任何授權需求。
  • 驗證中介軟體不會短路的,但不需要成功。

下列程式碼會限制只有已驗證使用者能存取 LogoutModelRazor Page:

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

    }

    public async Task<IActionResult> OnPostAsync()
    {

    }
}

如需有關如何在全域範圍內要求所有使用者進行驗證的資訊,請參閱需要驗證的使用者

授權屬性和 Razor Pages

AuthorizeAttribute「無法」套用至 Razor Page 處理常式。 例如,[Authorize] 無法套用至 OnGetOnPost 或任何其他頁面處理常式。 請考慮針對不同處理常式具有不同授權需求的頁面使用 ASP.NET Core MVC 控制器。 當需要不同的授權需求時,請使用 MVC 控制器:

  • 這是最不複雜的方法。
  • 這是 Microsoft 建議的方法。

如果您決定不使用 MVC 控制器,可以使用下列兩種方法將授權套用至 Razor Page 處理常式方法:

  • 針對需要不同授權的頁面處理常式使用不同的頁面。 將共用內容移至一或多個部分檢視。 可能的話,這是建議的方式。

  • 針對必須共用通用頁面的內容,請撰寫篩選,以在 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 範例方法「不會」

  • 使用套用至頁面、頁面模型或全域的授權屬性撰寫。 當您有多個 AuthorizeAttributeAuthorizeFilter 執行個體也套用至頁面時,撰寫授權屬性會導致驗證和授權執行多次。
  • 請與其餘 ASP.NET Core 驗證和授權系統搭配使用。 您必須確認使用此方法適用於您的應用程式。

Razor 頁面處理常式上沒有支援 AuthorizeAttribute 的計畫。