ASP.NET Core 中的簡單授權
ASP.NET Core 中的授權是由 [Authorize]
屬性及其各種參數所控制。 以最基本的形式,將 [Authorize]
屬性套用至控制器、動作或 Razor Page,即可限制只有已驗證的使用者能存取該元件。
必要條件
本文假設您已對 ASP.NET Core Razor Pages 和 MVC 有基本了解。 如果您不熟悉 ASP.NET Core,請參閱下列資源:
- ASP.NET Core 中的 Razor Pages 簡介
- ASP.NET Core MVC 概觀
- 教學課程:開始使用 ASP.NET Core 中的 Razor Pages
- Identity on ASP.NET Core 簡介
使用 [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()
{
}
}
只有已驗證的使用者允許存取 AccountController
,但 Login
動作除外,無論已驗證或未經驗證 / 匿名狀態為何,每個人都可以存取此動作。
警告
[AllowAnonymous]
略過授權陳述式。 如果您結合 [AllowAnonymous]
和 [Authorize]
屬性,則會略過 [Authorize]
屬性。 例如,如果您在控制器層級套用 [AllowAnonymous]
:
- 系統會忽略來自相同控制器上
[Authorize]
屬性或控制器上動作方法的任何授權需求。 - 驗證中介軟體不會短路的,但不需要成功。
下列程式碼會限制只有已驗證使用者能存取 LogoutModel
Razor Page:
[Authorize]
public class LogoutModel : PageModel
{
public async Task OnGetAsync()
{
}
public async Task<IActionResult> OnPostAsync()
{
}
}
如需有關如何在全域範圍內要求所有使用者進行驗證的資訊,請參閱需要驗證的使用者。
授權屬性和 Razor Pages
AuthorizeAttribute「無法」套用至 Razor Page 處理常式。 例如,[Authorize]
無法套用至 OnGet
、OnPost
或任何其他頁面處理常式。 請考慮針對不同處理常式具有不同授權需求的頁面使用 ASP.NET Core MVC 控制器。 當需要不同的授權需求時,請使用 MVC 控制器:
- 這是最不複雜的方法。
- 這是 Microsoft 建議的方法。
如果您決定不使用 MVC 控制器,可以使用下列兩種方法將授權套用至 Razor Page 處理常式方法:
針對需要不同授權的頁面處理常式使用不同的頁面。 將共用內容移至一或多個部分檢視。 可能的話,這是建議的方式。
針對必須共用通用頁面的內容,請撰寫篩選,以在 IAsyncPageFilter.OnPageHandlerSelectionAsync 中執行授權。 PageHandlerAuth GitHub 專案會示範此方法:
- AuthorizeIndexPageHandlerFilter 會實作授權篩選:
[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() { } }
- [AuthorizePageHandler] 屬性會套用至
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 範例方法「不會」:
- 使用套用至頁面、頁面模型或全域的授權屬性撰寫。 當您有多個
AuthorizeAttribute
或AuthorizeFilter
執行個體也套用至頁面時,撰寫授權屬性會導致驗證和授權執行多次。 - 請與 rest ASP.NET Core 驗證和授權系統搭配使用。 您必須確認使用此方法適用於您的應用程式。
Razor 頁面處理常式上沒有支援 AuthorizeAttribute
的計畫。