ASP.NET Core 中的 JWT 鉴权实现

360影视 2025-01-17 11:10 2

摘要:在当今的软件开发中,安全性和用户认证是至关重要的方面。JSON Web Token(JWT)作为一种流行的身份验证机制,因其简洁性和无状态特性而被广泛应用于各种应用中,尤其是在 ASP.NET Core 项目里。本文将详细介绍如何在 ASP.NET Core

在当今的软件开发中,安全性和用户认证是至关重要的方面。JSON Web Token(JWT)作为一种流行的身份验证机制,因其简洁性和无状态特性而被广泛应用于各种应用中,尤其是在 ASP.NET Core 项目里。本文将详细介绍如何在 ASP.NET Core 应用中实现 JWT 鉴权,确保应用能够安全地验证用户身份并授权访问特定资源。

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

这个包提供了 JWT 身份验证所需的所有功能,包括对 JWT 令牌的解析和验证。

在应用的配置文件appsettings.json中添加 JWT 相关的配置信息。这些配置包括密钥、发行者、受众和令牌的有效期等:{
"JwtSettings": {
"Secret": "YourSecretKeyYourSecretKeyYourSecretKeyYourSecretKey",// 用于加密的密钥(应非常复杂)
"Issuer": "YourAppName",// 发行者
"Audience": "YourAppUsers",// 受众
"ExpireMinutes":120// 令牌有效期
}
}在Program.cs文件中,需要配置 JWT 认证方案,以便 ASP.NET Core 知道如何处理 JWT 令牌:var builder = WebApplication.CreateBuilder(args);

var jwtSettings = builder.Configuration.GetSection("JwtSettings");

builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer =true
ValidateAudience =true
ValidateLifetime =true
ValidateIssuerSigningKey =true
ValidIssuer = jwtSettings["Issuer"],
ValidAudience = jwtSettings["Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["Secret"])),
ClockSkew = TimeSpan.Zero// 默认的 5 分钟偏移时间
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var token = context.Request.Headers["Authorization"].ToString?.Replace("Bearer ", "");
if (!string.IsOrEmpty(token))
{
context.Token = token;
}
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
// 如果过期,把过期信息添加到头部
if (context.Exception.GetType == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Append("Token-Expired", "true");
}

}
};
});

var app = builder.Build;
app.UseAuthentication;
app.UseAuthorization;

配置了 JWT 身份验证的中间件,确保所有传入的请求都会被检查是否包含有效的 JWT 令牌。

JwtBearerEvents的订阅事件

// 1. **OnMessageReceived**:
// -触发时机:当接收到一个身份验证请求。
// -用途:用来处理接收到的原始身份验证消息,可以根据请求的具体情况来修改或取消身份验证过程。

//2. * *OnTokenValidated * *:
// -触发时机:在JWT被成功验证后触发。
// -用途:用来处理已验证的token,例如,可以在这里添加额外的日志记录或执行一些安全检查。

//3. * *OnAuthenticationFailed * *:
// -触发时机:当身份验证失败时触发。
// -用途:用来处理身份验证失败的情况,例如,记录失败原因、执行额外的错误处理逻辑等。

//4. * *OnChallenge * *:
// -触发时机:当需要向客户端发出一个挑战(例如,要求客户端提供凭据)时触发。
// -用途:自定义挑战的响应,例如,修改返回给客户端的`401 Unauthorized`响应。

//5. * *OnForbidden * *:
// -触发时机:当授权失败时触发(即用户已通过身份验证,但没有足够的权限访问特定资源)。
// -用途:自定义处理禁止访问的情况,例如,返回一个自定义的错误消息或执行其他逻辑。

为了使用户能够登录并获取 JWT 令牌,需要创建一个控制器或服务来处理登录请求并生成 JWT 令牌。以下是一个简单的登录 API 示例:

using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

[ApiController]
[Route("api/[controller]")]
publicclassAuthController:ControllerBase
{
privatereadonly IConfiguration _configuration;

publicAuthController(IConfiguration configuration)
{
_configuration = configuration;
}

[HttpPost("login")]
public IActionResultLogin([FromBody] LoginRequest loginRequest)
{
// 假设已经验证了用户名和密码
if (loginRequest.Username == "admin" && loginRequest.Password == "password")
{
var token = GenerateJwtToken(loginRequest.Username);
return Ok(new { token });
}
return Unauthorized;
}

privatestringGenerateJwtToken(stringusername)
{
var jwtSettings = _configuration.GetSection("JwtSettings");
var claims = new
{
new Claim(JwtRegisteredClaimNames.Sub, username),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid.ToString)
//添加更多的标识
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["Secret"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

var token = new JwtSecurityToken(
issuer: jwtSettings["Issuer"],
audience: jwtSettings["Audience"],
claims: claims,
expires: DateTime.Now.AddMinutes(double.Parse(jwtSettings["ExpireMinutes"])),
signingCredentials: creds
);

returnnew JwtSecurityTokenHandler.WriteToken(token);
}
}

publicclassLoginRequest
{
publicstringUsername { get; set; }
publicstringPassword { get; set; }
}

一旦有了 JWT 令牌生成机制,接下来需要保护 API 路由,确保只有携带有效 JWT 令牌的请求可以访问受保护的资源。

可以通过在控制器或操作方法上使用[AllowAnonymous]可跳过授权[ApiController]
[Route("[controller]")]
[Authorize]
publicclassWeatherForecastController:ControllerBase
{

[Authorize]
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerableGet
{
return Enumerable.Range(15).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-2055),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray;
}
}客户端在请求受保护的 API 时,必须在请求头中添加Authorization字段,格式为:GET /api/protected/data HTTP/1.1
Host: yourdomain.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

这样,服务器就能通过 JWT 中间件验证令牌的有效性,并允许或拒绝请求。

需要使用包Swashbuckle.AspNetCore

builder.Services.AddSwaggerGen(options => options.SwaggerTokenConfigure);
if (app.Environment.IsDevelopment)
{
app.UseSwagger;
app.UseSwaggerUI;
}

SwaggerConfiguration将token保存到swagger并传递到后台

public staticclassSwaggerConfiguration
{
public static voidSwaggerTokenConfigure(this SwaggerGenOptions options)
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "JWT Auth API",
Version = "v1",
Description = "A sample API for JWT Authentication"
});

options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme.",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "Bearer",
BearerFormat = "JWT"
});

options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Emptystring
}
});
}
}

老规矩,先注册

builder.Services.AddHttpContextAccessor;
builder.Services.AddSingleton;
builder.Services.AddTransient;

存放用户信息的接口和实现类

public interfaceIAppUser
{
stringUsername { get; }
stringHeaderToken { get; }
}

publicclassAppUser:IAppUser
{
privatereadonly HttpContext _httpContext;
publicAppUser(IHttpContextAccessor httpContextAccessor)
{
_httpContext = httpContextAccessor?.HttpContext;
}

publicstringUsername { get => _httpContext?.User.Claims.FirstOrDefault(s => s.Type == "Username")?.Value.ToString??""; }

publicstringHeaderToken
{
get
{
if (_httpContext.Request.Headers.ContainsKey("Authorization"))
{
return _httpContext?.Request.Headers["Authorization"].ToString
.Replace("Bearer ", "").Trim;
}
returnstring.Empty;
}
}
}

直接使用

private readonly IAppUser _appUser ;

publicAuthController(IConfiguration configuration, IAppUser appUser)
{
_configuration = configuration;
_appUser=appUser;
}
[HttpGet]
public IActionResultGetuserinfo
{
return Ok(new { _appUser.Username, _appUser.HeaderToken });
}

可以成功获取到用户存放的token信息,不过现在还有一个弊端,就是每次都需要构造注入才可以过去用户信息,是比较麻烦的,其实我们可以通过封装一下,将AppUser存放到App全局配置里面直接静态获取,这样在需要获取用户信息的时候,就不需要每次都构造注入了等后面有机会出优化和封装教程,或者直接参考:https://gitee.com/Pridejoy/MalusAdmin

如果应用需要基于角色进行授权,可以在生成 JWT 令牌时添加角色信息:

private stringGenerateJwtToken(stringusername)
{
var claims = new
{
new Claim(JwtRegisteredClaimNames.Sub, username),
new Claim(ClaimTypes.Role, "Admin"),// 添加角色
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid.ToString)
};
// 剩余代码与前面一致
}然后,可以使用[Authorize(Roles = "Admin")]特性来限定只有特定角色的用户才能访问:

通过以上操作,就可以在 ASP.NET Core 应用中实现 JWT 鉴权,确保你的应用能够安全地验证用户身份并授权访问特定资源。JWT 的无状态特性和灵活性使其成为现代 Web 应用中身份验证的理想选择。

Net分享”,技术文章第一时间推送,随缘更新 , 分享一些你可能注意不到的细节。

来源:opendotnet

相关推荐