1、【什么是JWT】
- JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。
- JWT的官网地址:https://jwt.io/
- 通俗地来讲,JWT是能代表用户身份的令牌,可以使用JWT令牌在api接口中校验用户的身份以确认用户是否有访问api的权限。
- JWT中包含了身份认证必须的参数以及用户自定义的参数,JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。
2、【什么时候应该使用JSON Web令牌?】
1.授权:这是使用JWT的最常见方案。一旦用户登录,每个后续请求将包括JWT,允许用户访问该令牌允许的路由,服务和资源。Single Sign On是一种现在广泛使用JWT的功能,因为它的开销很小,并且能够在不同的域中轻松使用。
2.信息交换:JSON Web令牌是在各方之间安全传输信息的好方法。因为JWT可以签名 — 例如,使用公钥/私钥对 — 您可以确定发件人是他们所说的人。此外,由于使用标头和有效负载计算签名,您还可以验证内容是否未被篡改。
3、【JWT令牌结构】
在紧凑的形式中,JSON Web Tokens由dot(.
)分隔的三个部分组成,它们是:
- Header 头
- Payload 有效载荷
- Signature 签名
因此,JWT通常如下所示:
xxxxx.yyyyy.zzzzz
1.Header 头
标头通常由两部分组成:令牌的类型,即JWT,以及正在使用的签名算法,例如HMAC SHA256或RSA。
例如:
{
"alg": "HS256",
"typ": "JWT"
}
然后,这个JSON被编码为Base64Url,形成JWT的第一部分。
2.Payload 有效载荷
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
加密之后得到的token样式分为三部分组成。

如果您想使用JWT并将这些概念付诸实践,您可以使用jwt.io Debugger来解码,验证和生成JWT。
废话不多说,下面直接上代码(依赖注入使用Visual Studio 2022):
首先我们新建一个Demo asp.net core 空web项目

新建Token控制器,代码如下:
[Route("api/[controller]/[action]")]
[ApiController]
public class TokenController : ControllerBase
{
private readonly IConfiguration _configuration;
public TokenController(IConfiguration configuration)
{
_configuration = configuration;
}
public IActionResult GetToken(UserLoginInputDtoModel userLoginInput)
{
if (userLoginInput.UserName != "admin" && userLoginInput.Password != "admin")
return BadRequest("账号错误");
DateTime nowDateTime = DateTime.Now;
IConfigurationSection jwtConfig = _configuration.GetSection("Jwt");
string JsonWebKey= SecurityAlgorithms.HmacSha512;
string secret= jwtConfig.GetValue<string>("Secret");
SigningCredentials securityKey = new SigningCredentials(new SymmetricSecurityKey
(Encoding.ASCII.GetBytes(secret)), JsonWebKey);
List<Claim> claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Iss, jwtConfig.GetValue<string>("Issuer")),
new Claim(JwtRegisteredClaimNames.Aud, jwtConfig.GetValue<string>("Audience")),
new Claim(JwtRegisteredClaimNames.Name, userLoginInput.UserName),
new Claim(JwtRegisteredClaimNames.Email, userLoginInput.Password),
new Claim("ex",nowDateTime.ToString(CultureInfo.InvariantCulture))
};
SecurityToken securityToken = new JwtSecurityToken(
signingCredentials: securityKey,
expires: nowDateTime.AddMinutes(1),//过期时间
claims: claims
);
return Content(new JwtSecurityTokenHandler().WriteToken(securityToken));
}
这里就可以得到一个token值。
得到token值之后怎么做拦截呢?比如token验证未通过把请求拦截下来,这是就需要用到JWT校验事件了。具体做法如下:
在需要验证的控制器或方法上打上[Authorize]标记,如:
[Authorize]
public IActionResult GetTodo()
{
return Content("ddd");
}
验证事件在Program.cs(配置信息在appsettings.json中配置)中编写,如下:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseUrls("http://192.168.1.110:9010");
// Add services to the container.
builder.Configuration.AddJsonFile("appsettings.json");
builder.Services.AddControllersWithViews();
//注入服务 WebAPI访问控制
//1 携带token访问,返回了想要的数据 2 未携带token,返回401
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,//是否验证Issuer
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidateAudience = true,//是否验证Audience
ValidAudience = builder.Configuration["Jwt:Audience"],
ValidateLifetime = true,//是否验证失效时间
ClockSkew = TimeSpan.FromSeconds(5),
ValidateIssuerSigningKey = true,//是否验证SecurityKey
IssuerSigningKey =
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Secret"])),
};
options.Events = new JwtBearerEvents()
{
//验证是否传入token
OnMessageReceived = context =>
{
context.Token = context.Request.Query["Authorization"];
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
// 如果过期,则把<是否过期>添加到,返回头信息中
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
//context.Response.Headers.Add("Token-Expired", "true");
//自定义自己想要返回的数据结果,我这里要返回的是Json对象,
通过引用Newtonsoft.Json库进行转换
var payload = JsonConvert.SerializeObject(new { Code = "401",
Message = "很抱歉,Token无效或已过期" });
//自定义返回的数据类型
context.Response.ContentType = "application/json";
//自定义返回状态码,默认为401 我这里改成 200
context.Response.StatusCode = StatusCodes.Status200OK;
//输出Json数据结果
context.Response.WriteAsync(payload);
// return Task.FromResult(0);
}
return Task.CompletedTask;
}
};
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
///添加jwt验证
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
这时当我们携带token请求时会返回正确结果,反之则返回401错误提示
需要安装的SDK如下,可通过NuGet安装:
