ASP.NET Core 中的简单授权
ASP.NET Core 中的授权通过 [Authorize]
属性及其各种参数控制。 在其最基本的形式中,通过向控制器、操作或 Razor Page 应用 [Authorize]
属性,可限制为仅允许经过身份验证的用户访问该组件。
先决条件
本文假定你对 ASP.NET Core Razor Pages 和 MVC 有基本的了解。 如果不熟悉 ASP.NET Core,请参阅以下资源:
- ASP.NET Core 中的 Razor Pages 简介
- ASP.NET Core MVC 概述
- 教程:在 ASP.NET Core 中开始使用 Razor Pages
- ASP.NET Core 上的 Identity 简介
使用 [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 页面:
[Authorize]
public class LogoutModel : PageModel
{
public async Task OnGetAsync()
{
}
public async Task<IActionResult> OnPostAsync()
{
}
}
有关如何全局要求所有用户进行身份验证的信息,请参阅需要通过身份验证的用户。
授权属性和 Razor Pages
AuthorizeAttribute 不能应用于 Razor 页面处理程序。 例如,[Authorize]
不能应用于 OnGet
、OnPost
或任何其他页面处理程序。 请考虑使用 ASP.NET Core MVC 控制器来处理对不同处理程序有不同授权要求的页面。 在需要不同授权要求时使用 MVC 控制器:
- 是最简单的方法。
- 是 Microsoft 推荐的方法。
如果你决定不使用 MVC 控制器,可以使用以下两种方法向 Razor 页面处理程序方法应用授权:
为需要不同授权的页面处理程序使用不同的页面。 将共享内容移动到一个或多个分部视图中。 如果可能,建议使用这种方法。
对于必须共享公共页面的内容,请编写执行授权的筛选器作为 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() { } }
- 向
OnPostAuthorized
页面处理程序应用 [AuthorizePageHandler] 属性:
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
实例,撰写授权属性会导致多次执行身份验证和授权。 - 与 ASP.NET Core 身份验证和授权系统的 rest 结合使用。 你必须验证此方法是否适用于你的应用程序。
暂未计划在 Razor 页面处理程序上支持 AuthorizeAttribute
。