JWT身份验证教程
- 通过 NuGet 安装 Microsoft.AspNetCore.Authentication.JwtBearer
打开 Startup.cs 在 ConfigureServices 添加如下代码
services.AddScoped<IUserService, UserService>(); //将appsettings.json中的jwtsettings部分读取到jwtsettings中,给其他地方用 services.Configure<JwtSettings>(config.GetSection("JwtSettings")); //由于初始化的时候我们就需要用,所有用bind方法读取配置 var jwtSettings = new JwtSettings(); config.Bind("JwtSettings", jwtSettings); //添加身份验证 services.AddAuthentication(option => { //认证middleware配置 option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(o => { //jwt token参数设置 o.TokenValidationParameters = new TokenValidationParameters { NameClaimType = JwtClaimTypes.Name, RoleClaimType = JwtClaimTypes.Role, //token颁发机构 ValidIssuer = jwtSettings.Issuer, //颁发给谁 ValidAudience = jwtSettings.Audience, //这里的key要加密 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey)) }; });
Configure 配置认证中间件
app.UseAuthentication();//认证中间件
创建登录用实体类,也可以直接使用 Identity Server 的,这里图个方便
public class LoginInput { public string Username { get; set; } public string Password { get; set; } }
创建一个UserService类用于验证用户凭据和返回JWT令牌
文件的顶部包含一个定义用户服务的接口,下面是实现该接口的具体用户服务类。
身份验证成功后,该
Authenticate()
方法将使用JwtSecurityTokenHandler
该类生成JWT(JSON Web令牌),该类将生成使用存储在appsettings.json
中的密钥进行数字签名的令牌。标准中注册的声明 (建议但不强制使用) :
- iss: jwt签发者
- sub: jwt所面向的用户
- aud: 接收jwt的一方
- exp: jwt的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该jwt都是不可用的.
- iat: jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
public interface IUserService { Task<AuthenticateResponse> Authenticate(LoginDto model); } public class UserService : IUserService { private readonly UserManager<IdentityUser> _userManager; public JwtSettings _JwtSettings { get; } public UserService(UserManager<IdentityUser> userManager, IOptions<JwtSettings> jwtSettings) { this._userManager = userManager; this._JwtSettings = jwtSettings.Value; } /// <summary> /// 进行身份验证 /// </summary> /// <param name="model">LoginDto模型</param> /// <returns>AuthenticateResponse</returns> public async Task<AuthenticateResponse> Authenticate(LoginDto model) { var user = await _userManager.FindByNameAsync(model.UserName); // 没用用户或密码错误返回null if (user == null && !await _userManager.CheckPasswordAsync(user, model.Password)) return null; // 验证成功 生成jwt令牌 var token = generateJwtToken(user); return new AuthenticateResponse(user, token); } //获取Jwt Token private string generateJwtToken(IdentityUser user) { var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim(JwtClaimTypes.Audience, _JwtSettings.Audience), new Claim(JwtClaimTypes.Issuer, _JwtSettings.Issuer), new Claim(JwtClaimTypes.Name, user.UserName), new Claim("id", user.Id.ToString()) }), Expires = DateTime.UtcNow.AddDays(1),//有效日期 SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_JwtSettings.SecretKey)), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); } }
添加登录控制器
[Route("api/[controller]")] [ApiController] public class UserController : ControllerBase { private readonly IUserService userService; public UserController(IUserService userService) { this.userService = userService; } /// <summary> /// 实现用户登录 post: /api/user/Login/model /// </summary> /// <param name="model">LoginInput</param> /// <returns></returns> [HttpPost] [Route("Login")] [AllowAnonymous] public async Task<IActionResult> Login(LoginInput model) { var response = await userService.Authenticate(model); if (response == null) return BadRequest(new { message = "用户名或密码错误" }); return Ok(response); } }
appsettings.json
"JwtSettings": { "Issuer": "https://localhost:44336", "Audience": "https://localhost:44336", "SecretKey": "Hello-key----------"//注意 必须达到16位 }