JWT身份验证在现代Web应用中广泛使用,主要用于安全地传输用户身份信息.
1.身份验证(用户登录后,服务器生成一个 JWT 并返回给客户端。客户端在后续请求中携带该 JWT,服务器通过验证 JWT 来确认用户身份)
2.授权(JWT 中可以包含用户的角色或权限信息(如 role: “admin”)。服务器根据 JWT 中的信息决定用户是否有权访问特定资源)
3.信息交换(JWT 可以包含一些非敏感的用户信息(如用户ID、用户名等),客户端可以解析 JWT 获取这些信息,而无需频繁请求服务器)
4.跨域支持(在前后端分离的架构中,前端和后端可能部署在不同的域名下。JWT 可以通过 HTTP 头部(如 Authorization: Bearer )传递,支持跨域请求)
5.无状态( JWT 本身包含了所有必要的信息(如用户ID、角色、过期时间等),服务器只需验证 JWT 的签名即可,无需在服务器端存储会话状态。)
工作流程
JWT 在身份验证中的典型工作流程如下:
用户登录:用户向服务器发送用户名和密码进行登录。
服务器验证:服务器验证用户的凭据。如果验证成功,服务器会创建一个 JWT 并将其返回给客户端。
客户端存储:客户端接收到 JWT 后,通常将其存储在本地(如 localStorage 或 sessionStorage)。
后续请求:在后续的请求中,客户端将 JWT 包含在请求的 Authorization 头中,格式为 Bearer 。
服务器验证:服务器接收到请求后,验证 JWT 的签名和有效性。如果验证通过,服务器将处理请求并返回响应。
使用
1.安装所需的 NuGet 包
System.IdentityModel.Tokens.Jwt(7.7.1)
Microsoft.AspNetCore.Authentication.JwtBearer(8.0.13)
2.appsettings.json加配置
"Jwt": {"mess":"jwt用于方法认证和存储用户登录信息","Issuer": "MyWebAPI","Audience": "MyClientApp","Key": "A86DA130-1B95-4748-B3B2-1B6AA9F2F743","ExpireHours": 24 //过期时间
}
3.Program.cs入口文件jwt配置
// php 添加 JWT 身份验证 -----------------------
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{options.TokenValidationParameters = new TokenValidationParameters{ValidateIssuer = true, //是否验证发行商ValidateAudience = true,//是否验证受众者ValidateLifetime = true, //是否验证失效时间ValidateIssuerSigningKey = true, //是否验证签名键ValidIssuer = builder.Configuration["Jwt:Issuer"],ValidAudience = builder.Configuration["Jwt:Audience"],IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))};
});// JWT启用身份验证和授权
app.UseAuthentication();
app.UseAuthorization();
4.需要一个生成jwt token的地方,参考UserController.cs中GenerateJwtToken方法
/// <summary>
/// 生成jwt https://jwt.io/
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
private string GenerateJwtToken(string username)
{var key = _configuration["Jwt:Key"];if (string.IsNullOrEmpty(key) || Encoding.UTF8.GetByteCount(key) < 32){throw new ArgumentException("JWT Key 必须至少为 256 位(32 字节)。");}var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));//安全密钥var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);//安全算法//创建 JWT(JSON Web Token)中的声明Claims。声明是JWT的核心部分用于存储用户的相关信息(如用户名、角色等)以便在身份验证和授权过程中使用。var claims = new[]{new Claim(JwtRegisteredClaimNames.Sub, username),//用户名new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),//用户的登录生成的Guidnew Claim(ClaimTypes.Role, "Admin")//用户的角色,根据登录时用户的角色,填进去 生成,后面api可以加这个权限[Authorize(Roles = "Admin")]};var token = new JwtSecurityToken(issuer: _configuration["Jwt:Issuer"],//签发audience: _configuration["Jwt:Audience"],//接收claims: claims,//用户信息expires: DateTime.Now.AddHours(Convert.ToDouble(_configuration["Jwt:ExpireHours"])),//过期时间signingCredentials: credentials);return new JwtSecurityTokenHandler().WriteToken(token);
}
5.测试-----给方法加上授权特性[Authorize(Roles = “Admin,Manager”)]或者[Authorize]
/// <summary>
/// 测试方法,带权限
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize(Roles = "Admin,Manager")]
public IActionResult TsetJwt1()
{return Ok(new { message = "有权限访问这个方法!" });
}
/// <summary>
/// 不带权限
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize]
public IActionResult TsetJwt2()
{var jwtToken = "";var authorizationHeader = Request.Headers["Authorization"].ToString();if (!string.IsNullOrEmpty(authorizationHeader) && authorizationHeader.StartsWith("Bearer ")){jwtToken = authorizationHeader.Substring("Bearer ".Length).Trim();}return new JsonResult(jwtToken);
}
6.用户登录后得到jwt , 然后调用方法
后端登录
/// <summary>
/// 登录系统
/// 测试JWT JSON WEB TOKEN
/// </summary>
/// <returns></returns>
[HttpPost]
public IActionResult Login([FromBody] dynamic request)
{try{// 动态解析 JSON 字段string userid = request.GetProperty("userid").GetString();string password = request.GetProperty("password").GetString();// 简单的验证逻辑if (string.IsNullOrEmpty(userid) || string.IsNullOrEmpty(password)){return BadRequest("用户名密码不能为空");}string token ="";if (_User.Login(userid, password) != null) {token=GenerateJwtToken(userid);}return Ok(new { message = "登录成功", token = token });}catch (Exception e){Log4Helper.Error(e.ToString());return BadRequest(e.Message);}
前端登录
function login(){$.ajax({url: 'http://localhost:5279/api/User/Login',method: 'POST',contentType: 'application/json', // 设置请求头data: JSON.stringify({ userid:"php",password:"123456" }), // 发送 JSON 数据success: function (response) {$('#txt_token').val(response.token);},error: function (error) {$('#txt_token').val('登录失败:' + error.statusText);}});
}
前端调用方法
function jwt_test(){$.ajax({url: 'http://localhost:5279/api/User/TsetJwt1',method: 'GET',headers: {'Authorization': 'Bearer ' + $('#txt_token').val().trim() //加入jwt 确保去除多余空格},contentType: 'application/json', success: function (response) {alert(response.message);},error: function (error) {alert('请求失败' + error.statusText);}});console.log('JWT:', $('#txt_token').val());
}
https://jwt.io/ 这个地址可以解析jwt
这个时候登录后,得到jwt 后 去调用 带有[Authorize]的方法时,需要在header上加上这个jwt,不然访问不了,会提示401未授权。