1. 定义实体类
首先,定义一个与 JSON 配置结构匹配的实体类 JWTSetting用读取存放配置文件的值。
public class JWTSetting
{
public string SecretKey { get; set; }
public int ExpireHours { get; set; }
}
2. 配置 appsettings.json
确保你的 appsettings.json 文件中有如下配置:
"JWTSettingOption": {
"SecretKey": "thisistolongcode,andthishavestory@123321:KH>:&(*",
"ExpireHours": 10
}
3. 在 Program.cs 中注册配置
var builder = WebApplication.CreateBuilder(args);
// 绑定配置并注册到依赖注入容器
builder.Services.Configure<JWTSetting>(builder.Configuration.GetSection("JWTSettingOption"));
builder.Services.AddAuthentication(opt =>
{
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(opt =>
{
var jwtSetting = builder.Configuration.GetSection("JWTSettingOption").Get<JWTSetting>();
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSetting.SecretKey))
};
});
builder.Services.AddJWTService(); // 自定义
builder.Services.AddAuthorization();
// 在Swagger中可以像Hearder中添加 Authorization属性,用来传递JWT Token
builder.Services.AddSwaggerGen(c =>
{
var scheme = new OpenApiSecurityScheme()
{
Description = "JWT Authorization header using the Bearer scheme",
Reference = new OpenApiReference
{
Id = "Authorization",
Type = ReferenceType.SecurityScheme
},
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "oauth2",
Name = "Authorization",
};
c.AddSecurityDefinition("Authorization", scheme);
var requirement = new OpenApiSecurityRequirement();
requirement[scheme] = new List<string>();
c.AddSecurityRequirement(requirement);
});
// 使用身份验证中间件 必须在UseAuthorization之前
app.UseAuthentication();
// 使用授权中间件
app.UseAuthorization();
4. 使用依赖注入获取JWT服务配置
在需要使用配置的地方,通过构造函数注入 IOptionsSnapshot 来访问配置。
// 接口
public interface IJWTService
{
///
/// Generate token
///
///
///
///
string GenerateToken(long userId, string userName);
}
// 实现类服务
public class JWTService : IJWTService
{
private readonly IOptionsSnapshot<JWTSetting> _settings;
public JWTService(IOptionsSnapshot<JWTSetting> settings)
{
_settings = settings;
}
///
/// Generate token
///
///
///
///
public string GenerateToken(long userId, string userName)
{
// 生成秘钥实例
var secretKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_settings.Value.SecretKey));
// 生成签名凭证
var signingCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
// 生成声明集合
var claims = new System.Collections.Generic.List<System.Security.Claims.Claim>
{
new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Name, userName),
new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.NameIdentifier, userId.ToString())
};
// 生成过期时间
var expiresDate = DateTime.Now.AddHours(_settings.Value.ExpireHours);
// 生成 token
var token = new JwtSecurityToken(claims: claims, signingCredentials: signingCredentials, expires: expiresDate);
// 生成 token 字符串
var tokenStr = new JwtSecurityTokenHandler().WriteToken(token);
return tokenStr;
}
}
///
/// 自定义依赖注入帮助类
///
public static class DIHelper
{
///
/// 添加IServiceCollection 自定义扩展函数 JWT 服务
///
///
///
public static IServiceCollection AddJWTService(this IServiceCollection services)
{
return services.AddScoped<IJWTService, JWTService>();
}
}
5. 测试代码
使用 JWTTestController 进行登录检查。
[Route("api/[controller]/[action]")]
[ApiController]
public class JWTTestController
{
private readonly IJWTService _jwtService;
private readonly UserManager<MyUser> _userManager;
private readonly RoleManager<MyRole> _roleManager;
public JWTTestController(IJWTService jwtService, UserManager<MyUser> userManager, RoleManager<MyRole> roleManager)
{
_jwtService = jwtService;
_userManager = userManager;
_roleManager = roleManager;
}
///
/// 登录
///
///
///
[HttpPost]
public async Task<IActionResult> Login([FromBody] LoginModel login)
{
var user = await _userManager.FindByNameAsync(login.UserName);
if (user == null)
{
return new JsonResult(new { Code = 400, Message = "用户不存在" });
}
if (!await _userManager.CheckPasswordAsync(user, login.Password))
{
return new JsonResult(new { Code = 400, Message = "密码错误" });
}
var token = _jwtService.GenerateToken(user.Id, user.UserName);
return new JsonResult(new { Code = 200, Message = "登录成功", Token = token });
}
}
使用 TestController进行权限检查,添加[Authorize]注解,校验当前方法必须校验Token。
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController
{
private readonly UserManager<MyUser> _userManager;
private readonly RoleManager<MyRole> _roleManager;
public TestController(UserManager<MyUser> userManager, RoleManager<MyRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
// AllowAnonymous不校验该权限
[HttpGet]
[AllowAnonymous]
public async Task<ActionResult<string>> CheckAccount(string account, string password)
{
var user = await _userManager.FindByNameAsync(account);
if (user == null)
{
return "错误";
}
else
{
return "正确";
}
}
// 校验当前必须是admin权限才能操作
[HttpPost]
[Authorize(Roles ="admin")]
public async Task<ActionResult<string>> CreateUser(string account, string password)
{
var user = await _userManager.FindByNameAsync(account);
if (user == null)
{
user = new MyUser
{
UserName = account
};
var result = await _userManager.CreateAsync(user, password);
if (!result.Succeeded)
{
return "创建失败";
}
}
var role = await _roleManager.FindByNameAsync("admin");
if (role == null)
{
role = new MyRole
{
Name = "admin"
};
var result = await _roleManager.CreateAsync(role);
if (!result.Succeeded)
{
return "创建失败";
}
}
var result2 = await _userManager.AddToRoleAsync(user, "admin");
return "成功";
}
}