在 ASP.NET Core 中,授权断言(Authorization Assertion)是通过创建自定义的业务逻辑,用于在身份验证之后进行更细粒度的权限控制。授权断言允许你根据用户的身份和请求的上下文执行复杂的授权逻辑。它们通常与 策略授权(Policy-based Authorization)结合使用,通过定义自定义授权策略和授权处理程序(Authorization Handlers)来进行控制。
授权断言的主要应用场景
授权断言常用于以下场景:
- 验证用户是否拥有特定的角色或权限。
- 根据请求的上下文(例如请求参数)做出授权决策。
- 对资源的访问进行更加细致的控制,例如用户是否有权限修改某个资源。
1. 授权策略和授权断言的核心概念
- 授权策略(Authorization Policy): 定义哪些要求(如角色、声明等)用户需要满足才能访问某个资源。
- 授权断言(Authorization Requirement): 表示特定的授权要求,用于自定义权限逻辑。
- 授权处理程序(Authorization Handler): 负责处理
Authorization Requirement
,根据当前用户和上下文来判断是否满足授权要求。
2. 创建自定义的授权断言
步骤 1: 创建 IAuthorizationRequirement
授权断言的核心是实现 IAuthorizationRequirement
接口,定义需要满足的条件。
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public int MinimumAge { get; }
public MinimumAgeRequirement(int minimumAge)
{
MinimumAge = minimumAge;
}
}
上面的例子中,MinimumAgeRequirement
表示一个要求,即用户的年龄必须超过指定的最小年龄。
步骤 2: 创建授权处理程序
接下来,你需要创建一个授权处理程序(Authorization Handler),来处理这个授权要求。处理程序会根据业务逻辑来判断用户是否满足要求。
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MinimumAgeRequirement requirement)
{
// 获取用户的出生日期
if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth))
{
return Task.CompletedTask;
}
var dateOfBirth = Convert.ToDateTime(context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value);
int userAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-userAge))
{
userAge--;
}
// 如果用户的年龄大于等于要求的最小年龄,授权通过
if (userAge >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
在这个处理程序中,HandleRequirementAsync
方法负责处理逻辑。首先,它从用户的声明中获取出生日期,然后计算用户的年龄。如果用户的年龄满足要求的最小年龄,则调用 context.Succeed(requirement)
表示授权通过。
步骤 3: 注册自定义授权策略
现在,你需要在 Startup.cs
或 Program.cs
中注册自定义的授权策略以及处理程序。
public void ConfigureServices(IServiceCollection services)
{
// 添加授权服务,并定义自定义的策略
services.AddAuthorization(options =>
{
options.AddPolicy("AtLeast18", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(18)));
});
// 注册处理程序
services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
}
在这里,我们定义了一个名为 "AtLeast18"
的策略,该策略要求用户的年龄至少为 18 岁。然后我们将自定义的 MinimumAgeHandler
注册到依赖注入容器中。
步骤 4: 在控制器或操作方法中应用策略
你可以使用 [Authorize]
属性将这个自定义策略应用到控制器或某个具体的操作方法上:
[Authorize(Policy = "AtLeast18")]
[HttpGet]
public IActionResult GetAdultContent()
{
return Ok("You are old enough to see this content.");
}
只有满足 “AtLeast18” 策略的用户才能访问 GetAdultContent
这个操作方法。
3. 高级应用:基于资源的授权断言
有时,授权不仅仅取决于用户本身,还取决于资源。例如,一个用户是否有权限修改某个文档。这种情况下,可以使用基于资源的授权。
示例:基于资源的授权断言
首先,定义一个资源的授权要求:
public class Document
{
public string Author { get; set; }
}
public class IsOwnerRequirement : IAuthorizationRequirement
{
}
接着,创建处理程序来处理资源的授权逻辑:
public class IsOwnerHandler : AuthorizationHandler<IsOwnerRequirement, Document>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IsOwnerRequirement requirement, Document resource)
{
if (context.User.Identity?.Name == resource.Author)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
在这个处理程序中,我们根据资源的 Author
属性判断用户是否是该文档的作者,从而决定是否授权成功。
注册资源授权处理程序
同样,你需要在 Startup.cs
或 Program.cs
中注册处理程序:
services.AddSingleton<IAuthorizationHandler, IsOwnerHandler>();
在控制器中使用资源授权
你可以在控制器或服务中手动调用资源授权的逻辑:
[HttpGet]
public async Task<IActionResult> EditDocument(int documentId)
{
var document = GetDocumentById(documentId); // 从数据库获取文档
var authorizationResult = await _authorizationService.AuthorizeAsync(User, document, "IsOwner");
if (!authorizationResult.Succeeded)
{
return Forbid();
}
return Ok("You are authorized to edit this document.");
}
这里,我们使用了 IAuthorizationService
来手动触发基于资源的授权。AuthorizeAsync
方法接收当前用户、资源以及自定义的策略名称。如果用户被授权,可以继续执行操作,否则返回 Forbid()
响应。
总结
- 授权断言 用于实现自定义的授权逻辑,通常与策略授权相结合。
- 可以通过实现
IAuthorizationRequirement
和AuthorizationHandler
来定义并处理授权要求。 - 授权策略在
Startup.cs
或Program.cs
中进行注册,并可以应用到控制器或操作方法中。 - 基于资源的授权 允许你根据请求资源和用户的关联关系进行更细粒度的权限控制。
通过授权断言,你可以灵活地定制复杂的授权逻辑,以满足不同业务场景的权限需求。