使用
使用 IAuthorizationRequirementData 接口在属性定义中指定与授权策略关联的要求。
示例应用
本文中所述的完整示例是 AuthRequirementsData 示例应用(GitHub 存储库)(dotnet/AspNetCore.Docs.Samples如何下载)。 该示例应用为用户实现最低年龄处理程序,要求用户提供出生日期声明,指示他们至少为 21 岁。
最小年龄授权属性
IAuthorizationRequirementData 的 MinimumAgeAuthorizeAttribute 实现设置授权页面:
using Microsoft.AspNetCore.Authorization;
namespace AuthRequirementsData.Authorization;
class MinimumAgeAuthorizeAttribute(int age) : AuthorizeAttribute,
IAuthorizationRequirement, IAuthorizationRequirementData
{
public int Age { get; set; } = age;
public IEnumerable<IAuthorizationRequirement> GetRequirements()
{
yield return this;
}
}
最小年龄授权处理程序
MinimumAgeAuthorizationHandler 类处理 MinimumAgeAuthorizeAttribute 提供的单个 IAuthorizationRequirement,这通过泛型参数 MinimumAgeAuthorizeAttribute 来指定。
HandleRequirementAsync 方法:
- 获取用户的出生日期声明。
- 从声明获取用户的年龄。
- 如果用户今年还没有过生日,则调整年龄。
- 如果用户满足年龄要求,则标记授权要求成功。
- 实现日志记录以实现演示目的。
using System.Globalization;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
namespace AuthRequirementsData.Authorization;
class MinimumAgeAuthorizationHandler(ILogger<MinimumAgeAuthorizationHandler> logger)
: AuthorizationHandler<MinimumAgeAuthorizeAttribute>
{
// Check whether a given minimum age requirement is satisfied.
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
MinimumAgeAuthorizeAttribute requirement)
{
logger.LogInformation(
"Evaluating authorization requirement for age >= {age}",
requirement.Age);
// Get the user's birth date claim.
var dateOfBirthClaim =
context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth);
if (dateOfBirthClaim != null)
{
// If the user has a date of birth claim, obtain their age.
var dateOfBirth = Convert.ToDateTime(dateOfBirthClaim.Value,
CultureInfo.InvariantCulture);
var age = DateTime.Now.Year - dateOfBirth.Year;
// Adjust age if the user hasn't had a birthday yet this year.
if (dateOfBirth > DateTime.Now.AddYears(-age))
{
age--;
}
// If the user meets the age requirement, mark the authorization
// requirement succeeded.
if (age >= requirement.Age)
{
logger.LogInformation(
"Minimum age authorization requirement {age} satisfied",
requirement.Age);
context.Succeed(requirement);
}
else
{
logger.LogInformation(
"Current user's DateOfBirth claim ({dateOfBirth}) doesn't " +
"satisfy the minimum age authorization requirement {age}",
dateOfBirthClaim.Value,
requirement.Age);
}
}
else
{
logger.LogInformation("No DateOfBirth claim present");
}
return Task.CompletedTask;
}
}
该MinimumAgeAuthorizationHandler作为单例IAuthorizationHandler服务在应用的Program文件中注册。
builder.Services.AddSingleton<IAuthorizationHandler,
MinimumAgeAuthorizationHandler>();
在用户满足最低年龄政策的情况下,通过使用年龄为 21 岁的GreetingsController属性,[MinimumAgeAuthorize({AGE})]将显示用户的姓名,其中{AGE}占位符代表年龄。
using Microsoft.AspNetCore.Mvc;
using AuthRequirementsData.Authorization;
namespace AuthRequirementsData.Controllers;
[ApiController]
[Route("api/[controller]")]
public class GreetingsController : Controller
{
[MinimumAgeAuthorize(21)]
[HttpGet("hello")]
public string Hello() =>
$"Hello {HttpContext.User.Identity?.Name}!";
}
如果用户的出生日期声明指示他们至少为 21 岁,控制器将显示问候字符串,发出 200 (OK) 状态代码。 如果用户缺少出生日期声明或声明指示用户未满 21 岁,那么问候语将不会显示,并且系统会返回 403(禁止)状态代码。
JWT 持有者身份验证服务将添加到应用的 Program 文件中:
builder.Services.AddAuthentication().AddJwtBearer();
应用设置文件 (appsettings.json) 为 JWT 持有者身份验证配置受众和颁发者:
"Authentication": {
"Schemes": {
"Bearer": {
"ValidAudiences": [
"https://localhost:51100"
],
"ValidIssuer": "dotnet-user-jwts"
}
}
}
在前面的示例中,localhost 受众与应用启动配置文件(applicationUrl)中指定的 localhost 地址Properties/launchSettings.json匹配。
演示
使用 dotnet user-jwts 和 curl 测试示例。
在命令行界面中的项目文件夹中,执行以下命令创建一个 JWT 持有者令牌,该令牌的出生日期声明使用户超过 21 岁:
dotnet user-jwts create --claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth=1989-01-01
输出在命令 shell 中的“Token:”后面生成令牌:
New JWT saved with ID '{JWT ID}'.
Name: {USER}
Custom Claims: [http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth=1989-01-01]
Token: {TOKEN}
把标记的值(前面的输出中出现的 {TOKEN} 占位符)存起来,以便以后使用。
你可以在联机 JWT 解码器中解码令牌,例如 jwt.ms,以查看其内容,并显示其中包含一个带有用户出生日期的 birthdate 声明:
{
"alg": "HS256",
"typ": "JWT"
}.{
"unique_name": "{USER}",
"sub": "{USER}",
"jti": "{JWT ID}",
"birthdate": "1989-01-01",
"aud": [
"https://localhost:51100",
"http://localhost:51101"
],
"nbf": 1747315312,
"exp": 1755264112,
"iat": 1747315313,
"iss": "dotnet-user-jwts"
}.[Signature]
使用一个 dateofbirth 值再次执行该命令,该值使用户年龄低于 21 岁:
dotnet user-jwts create --claim http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth=2020-01-01
将第二个令牌的值暂存起来。
在 Visual Studio 中或使用 dotnet watch .NET CLI 中的命令启动应用。
在 .NET CLI 中,执行以下命令 curl.exe 来请求 api/greetings/hello 终结点。 将 {TOKEN} 占位符替换为之前保存的第一个 JWT 持有者令牌:
curl.exe -i -H "Authorization: Bearer {TOKEN}" https://localhost:51100/api/greetings/hello
输出指示成功,因为用户的出生日期声明指示他们至少为 21 岁:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Thu, 15 May 2025 22:58:10 GMT
Server: Kestrel
Transfer-Encoding: chunked
Hello {USER}!
日志记录指明满足了年龄要求:
MinimumAgeAuthorizationHandler: Information: Evaluating authorization requirement for age >= 21
MinimumAgeAuthorizationHandler: Information: Minimum age authorization requirement 21 satisfied
使用第二个令牌重新执行 curl.exe 命令,指示用户年龄低于 21 岁。 输出指示不满足要求。 禁止访问终结点(状态代码 403):
HTTP/1.1 403 Forbidden
Content-Length: 0
Date: Thu, 15 May 2025 22:58:36 GMT
Server: Kestrel
MinimumAgeAuthorizationHandler: Information: Evaluating authorization requirement for age >= 21
MinimumAgeAuthorizationHandler: Information: Current user's DateOfBirth claim (2020-01-01) doesn't satisfy the minimum age authorization requirement 21