问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

ASP.NET Core JWT认证与授权详解

创作时间:
作者:
@小白创作中心

ASP.NET Core JWT认证与授权详解

引用
CSDN
1.
https://blog.csdn.net/chenbin520/article/details/146024155

JWT(JSON Web Token)是目前最流行的跨域认证解决方案之一,特别是在微服务架构中。本文将详细介绍如何在ASP.NET Core中实现JWT认证与授权,包括JWT的结构、认证服务的配置、Token的生成与验证,以及详细的源代码分析。

1. JWT结构

JSON Web Token(JWT)是一种用于在网络应用之间安全传输声明的开放标准(RFC 7519)。它通常由三部分组成,以紧凑的字符串形式表示,在身份验证、信息交换等场景中广泛应用。

2. JWT权限认证

2.1 添加认证服务类

在Program类中添加认证服务、Jwt处理类以及JWT配置项。

// 配置 JWT 身份验证
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["JwtOptions:Issuer"],
            ValidAudience = builder.Configuration["JwtOptions:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["JwtOptions:SecurityKey"]))
        };
    });

2.2 配置认证中间件

当前端发送请求到后端时,会通过Authentication中间件解析前端发送过来的Bearer,并把解析的数据填充到HttpContext.User中。

app.UseAuthentication();

2.3 生成Token

public string IssueToken()
{
    var signinCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey)), SecurityAlgorithms.HmacSha256);
    var cls = new List<Claim>()
        {
            new Claim(ClaimTypes.Name, "admin"),
            new Claim("org", "001")
        };
    var tokeOptions = new JwtSecurityToken(
        issuer: jwtOptions.Issuer,
        audience: jwtOptions.Audience,
        claims: cls,
        expires: DateTime.UtcNow.AddSeconds(6400),
        signingCredentials: signinCredentials
    );
    var token = new JwtSecurityTokenHandler().WriteToken(tokeOptions);
    return token;
}

2.4 appsettings中jwt配置

"JwtOptions": {
  "Issuer": "http://localhost",
  "Audience": "http://localhost",
  "Expires": 3600,
  "SecurityKey": "ThisIsASecretKeyThatIsAtLeast32BytesLongForHS256Algorithm"
}

配置项注入

builder.Services.Configure<JwtOptions>(builder.Configuration.GetSection("JwtOptions"));

2.5 获取认证信息

如果验证成功,就可以从HttContext.User中获取到相关信息。如:HttpContext.User.Identity.IsAuthenticated、HttpContext.User.Identity.Name等。

var user = HttpContext.User;

3. Authentication源代码分析

3.1 JWT认证主要涉及以下类

3.2 业务流程

3.3 业务分析

  • 执行AddJwtBearer(options =>{…})方法,往AuthenticationOptions添加AuthenticationSchemeBuilder。
  • 执行AuthenticationMiddleware时,先注入IAuthenticationSchemeProvider对象,IAuthenticationSchemeProvider会通过注入AuthenticationOptions,生成AuthenticationScheme列表。
  • 遍历AuthenticationScheme列表,通过IAuthenticationHandlerProvider对象构建IAuthenicationRequestHandler实例。(IAuthenticationHandlerProvider通过注入IAuthenticationSchemeProvider对象,根据scheme名称找到AuthneticationScheme实例,再找到HandlerType,根据HandlerType生成实例)。
  • 调用JwtBearerHandler解析Bearder,只要有一个Handler处理成功,就结束。

4. 授权

4.1 授权配置

可以通过配置[Authorize]特性,使得方法的调用必须验证授权。

  • [Authorize]不带任何参数,只验证用户是否登录
[Authorize]
public IActionResult Privacy()
  • [Authorize(Roles =“admin”)]配置角色,验证用户是否属于要求的角色。角色是或者的关系,只需要满足一个就验证通过。
[Authorize(Roles ="admin,operate")]
public IActionResult Privacy()
  • 自定义配置策略
[Authorize("MinimumAgePolicy")]
public string Test()
// 添加验证策略,策略是且的关系,必须全部满足才验证通过
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("MinimumAgePolicy", policy => policy.Requirements.Add(new MinimumAgeRequirement(18)));
});

public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MinimumAgeRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth))
        {
            var dateOfBirth = Convert.ToDateTime(context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value);
            var age = DateTime.Today.Year - dateOfBirth.Year;
            if (dateOfBirth > DateTime.Today.AddYears(-age))
            {
                age--;
            }
            if (age >= requirement.MinimumAge)
            {
                context.Succeed(requirement);
            }
        }
        return Task.CompletedTask;
    }
}
public class MinimumAgeRequirement : IAuthorizationRequirement
{
    public int MinimumAge { get; set; }
    public MinimumAgeRequirement(int minimumAge)
    {
        MinimumAge = minimumAge;
    }
}

5. Authorization源码分析

5.1 类图

5.2 代码分析

以下代码在AuthorizationOptions类中添加AuthorizationPolicy,每个AuthorizationPolicy包含多个IAuthorizationRequirement。每个IAuthorizationRequirement代表一个验证项。

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("MinimumAgePolicy", policy => policy.Requirements.Add(new MinimumAgeRequirement(18)));
});


  • 注入中间件AuthorizationMiddleware,当请求到达时,中间件会获取当前EndPoint信息(IAuthorizeData),如根据[Authorize(“MinimumAgePolicy”)]获取AuthorizationPolicy。
  • 获取AuthorizationPolicy会判断是否有配置Roles,如果有配置,则会在Policy对象中添加RolesAuthorizationRequirement对象。(policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData, policies)😉
  • 调用DefaultAuthorizationService,验证AuthorizationPolicy。
  • DefaultAuthorizationService会获取所有注入的IAuthorizationHandler,遍历所有的Handler,根据Handler所要求的Requirement,从AuthorizationPolicy中获取实例传入Handler中。Handler验证成功,会删除对应的Requirement。所有Requirement都删除了才算验证成功。
app.UseAuthorization();

针对系统自带Requirement,比如配置Roles添加RolesAuthorizationRequirement对象。在AddAuthorization->AddAuthorizationCore中会注入PassThroughAuthorizationHandler。该Handler会遍历系统自带的Requirement(系统自带的Requirement会继承AuthorizationHandler并实现IAuthorizationRequirement),直接调用HandleAsync方法。

services.TryAddEnumerable(ServiceDescriptor.Transient<IAuthorizationHandler, PassThroughAuthorizationHandler>());
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号