JWT在.NET8 Webapi中的使用

发布于:2025-03-11 ⋅ 阅读:(20) ⋅ 点赞:(0)

在这里插入图片描述

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()),//用户的登录生成的Guid
        new 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未授权。