net8.0 使用JWT完成登录验证

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 "成功";
     }
 }

你可能感兴趣的:(.netcore)