JWT
song

什么是JWT

  • JSON Web Token(简称 JWT)是目前最流行的跨域认证解决方案。 jwt.io

  • 是一种认证授权机制。

  • JWT 是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准(RFC 7519)。

  • JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上。

  • 可以使用 HMAC 算法或者是 RSA 的公/私秘钥对 JWT 进行签名。因为数字签名的存在,这些传递的信息是可信的。

  • JWT 由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。

    1. 头部(Header):包含了关于生成该 JWT 的信息以及所使用的算法类型。
    2. 载荷(Payload):包含了要传递的数据,例如身份信息和其他附属数据。
    3. 签名(Signature):使用密钥对头部和载荷进行签名,以验证其完整性。

JWT的优缺点

  • 优点:
    1. 无需在服务器上存储令牌。去中心化,无状态,便于分布式系统使用
    2. 基本信息可以直接放在token中,存放在客户端。 userid,name,role
  • 缺点:
    1. 服务端不能主动让token失效
    2. payload的数据量

JWT 应用场景

常见的 JWT 应用常见有 JWT 授权和信息交换:

  • 授权:JWT 被应用最多的场景,用户登录后服务端响应一个 JWT,后续的请求都携带 JWT内容,以此验证用户身份。使用 JWT 可以进行单点登录,可以跨域。
  • 信息交换:因为 JWT 需要使用密钥进行签名,因此使用 JWT 安全的传输信息也是一个好方法,签名可以确保消息发送人没有问题,确保消息没有被篡改。

netcore实践

生成、解码jwt token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace jwt.console
{
/// <summary>
/// JwtSecurityTokenHandler
/// System.IdentityModel.Tokens.Jwt 和 Microsoft.IdentityModel.Tokens
/// </summary>
public class JwtTokenGenerator
{
private readonly string _key;

public JwtTokenGenerator(string securityKey)
{
if (securityKey.Length != 32) throw new ArgumentException("Key length must be 32 bytes.");
_key = securityKey;

}

public string GenerateToken(IEnumerable<Claim> claims, int expiresInMinutes = 60)
{
var keyBytes = Encoding.UTF8.GetBytes(_key);
var secKey = new SymmetricSecurityKey(keyBytes);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.UtcNow.AddMinutes(expiresInMinutes),
SigningCredentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}


public ClaimsPrincipal DecodeToken(string token)
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_key)),
ValidateIssuer = false,
ValidateAudience = false
// 根据需要设置ValidateIssuer和ValidateAudience
};
var tokenHandler = new JwtSecurityTokenHandler();
try
{
SecurityToken validatedToken;
var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out validatedToken);
return principal;
}
catch (SecurityTokenException ex)
{
// 处理Token验证失败的情况
throw;
}
}

}
}

Program调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using jwt.console;
using System.Security.Claims;
using System.Text;

namespace jwt_console
{
class Program
{
static void Main(string[] args)
{
var jwtTokenGenerator = new JwtTokenGenerator("avgfxchsggszy&@L!!!@IOfsfszlt2z333");
var claims = new List<Claim> { new Claim(ClaimTypes.Name, "liss") };
var token = jwtTokenGenerator.GenerateToken(claims);
var result = jwtTokenGenerator.DecodeToken(token);
Console.WriteLine(result.Claims.First(r => r.Type == ClaimTypes.Name).Value);

string[] segments = token.Split('.');
string head = ParseJwt(segments[0]);
string payload = ParseJwt(segments[1]);
Console.WriteLine("--------head--------");
Console.WriteLine(head);
Console.WriteLine("--------payload--------");
Console.WriteLine(payload);
}

static string ParseJwt(string s)
{
s = s.Replace('-', '+').Replace('_', '/');
switch (s.Length % 4)
{
case 2:
s += "==";
break;
case 3:
s += "=";
break;
}
var bytes = Convert.FromBase64String(s);
return Encoding.UTF8.GetString(bytes);
}
}
}

netcore完整的使用示例

  1. 添加依赖包 安装以下 NuGet 包,以便支持 JWT 身份验证:
    1
    NuGet\Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 6.0.35
  2. 添加JWT配置 appsettings.json
    1
    2
    3
    4
    "JwtConfig": {
    "SecretKey": "sdfas344gui*&*@!)@Y$IU@UI12fzgh2",
    "ExpireMinutes": 60
    }
  3. 创建生成jwt token类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    using Microsoft.Extensions.Options;
    using Microsoft.IdentityModel.Tokens;
    using System.IdentityModel.Tokens.Jwt;
    using System.Security.Claims;
    using System.Text;

    namespace jwt.api
    {
    /// <summary>
    /// JwtSecurityTokenHandler
    /// System.IdentityModel.Tokens.Jwt 和 Microsoft.IdentityModel.Tokens
    /// </summary>
    public class JwtTokenGenerator
    {
    private readonly string _key;

    private readonly IOptions<JwtConfig> _options;
    public JwtTokenGenerator(IOptions<JwtConfig> options)
    {
    _options = options;
    _key = _options.Value.SecretKey;
    if (_key.Length != 32) throw new ArgumentException("Key length must be 32 bytes.");
    }

    public string GenerateToken(string username)
    {
    var keyBytes = Encoding.UTF8.GetBytes(_key);
    var secKey = new SymmetricSecurityKey(keyBytes);
    var tokenDescriptor = new SecurityTokenDescriptor
    {
    Subject = new ClaimsIdentity(new Claim[] {
    new Claim(ClaimTypes.Name, username),
    new Claim(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString())
    }),
    Expires = DateTime.UtcNow.AddMinutes(_options.Value.ExpireMinutes),
    SigningCredentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature)
    };
    var tokenHandler = new JwtSecurityTokenHandler();
    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
    }
    }
    }

  4. 配置 JWT 身份验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using jwt.api;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddSwaggerGen();
builder.Services.Configure<JwtConfig>(builder.Configuration.GetSection("JwtConfig"));
builder.Services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
var jwtConfig = builder.Configuration.GetSection("JwtConfig").Get<JwtConfig>();
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SecretKey)), // 密钥应从配置文件中获取
};
});
builder.Services.AddScoped<JwtTokenGenerator>();

var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI();
app.UseAuthentication(); // 调用认证中间件
app.UseAuthorization(); // 调用授权中间件
app.MapControllers();
app.Run();
  1. 登录控制器 (AuthController.cs):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    using Microsoft.AspNetCore.Mvc;

    namespace jwt.api.Controllers
    {
    [Route("api/[controller]")]
    [ApiController]
    public class AuthController : ControllerBase
    {
    private readonly JwtTokenGenerator _tokenGenerator;
    public AuthController(JwtTokenGenerator tokenGenerator)
    {
    _tokenGenerator = tokenGenerator;
    }

    [HttpPost("login")]
    public IActionResult Login([FromBody] LoginModel model)
    {
    if (model.Username == "testuser" && model.Password == "password") // 这里你可以加入你的用户验证逻辑
    {
    var token = _tokenGenerator.GenerateToken(model.Username);
    return Ok(new { token });
    }
    return Unauthorized();
    }
    }

    public record LoginModel(string Username,string Password);
    }

    ```
    6. 受保护的 API (ValuesController.cs):
    ```C#
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;

    namespace jwt.api.Controllers
    {
    [Route("api/[controller]")]
    [ApiController]
    [Authorize] // 添加授权
    public class ValuesController : ControllerBase
    {
    [HttpGet]
    public IActionResult GetValues()
    {
    return Ok(new string[] { "value1", "value2" });
    }
    }
    }
  2. 调用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @host = http://localhost:5123

    POST {{host}}/api/auth/login
    Content-Type: application/json

    {
    "username":"testuser",
    "password":"password"
    }

    ###
    GET {{host}}/api/values
    Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6InRlc3R1c2VyIiwibmFtZWlkIjoiNjkzOGYyZTctMDcwOC00N2M1LWI1ZjAtN2I2ZDFlMTA3MGQwIiwibmJmIjoxNzI5MTQ2Mzg2LCJleHAiOjE3MjkxNDk5ODYsImlhdCI6MTcyOTE0NjM4Nn0.JwjlPsyjOvm3DyyJrVfGqmyLLXt-CzSd877WhHJLGFQ


由 Hexo 驱动 & 主题 Keep