介绍
JWT全称是JSON web token,它是使用JSON格式来保存令牌信息的。JWT机制不是把用户的登录信息保存在服务器端,而是把登录信息(也叫作令牌)保存在客户端。为了防止客户端的数据造假,保存在客户端的令牌经过了签名处理,而签名的密钥只有服务器端才知道,每次服务器端收到客户端提交的令牌的时候都要检查一下签名,如果发现数据被篡改,则拒绝接收客户端提交的令牌
- 头部(header)中保存的是加密算法的说明。
- 负载(payload)中保存的是用户的ID、用户名、角色等信息。
- 签名(signature)是根据头部和负载一起算出来的值。
JWT实现登录的流程如下。
- 客户端向服务器端发送用户名、密码等请求登录。
- 服务器端校验用户名、密码,如果校验成功,则从数据库中取出这个用户的ID、角色等用户相关信息。
- 服务器端采用只有服务器端才知道的密钥来对用户信息的JSON字符串进行签名,形成签名数据。
- 服务器端把用户信息的JSON字符串和签名拼接到一起形成JWT,然后发送给客户端。
- 客户端保存服务器端返回的JWT,并且在客户端每次向服务器端发送请求的时候都带上这个JWT。
- 每次服务器端收到浏览器请求中携带的JWT后,服务器端用密钥对JWT的签名进行校验,如果校验成功,服务器端则从JWT中的JSON字符串中读取出用户的信息。
这样服务器端就知道这个请求对应的用户了,也就实现了登录的功能。
由此可以看出,在JWT机制下,登录用户的信息保存在客户端,服务器端不需要保存数据,这样我们的程序就天然地适合分布式的集群环境,而且服务器端从客户端请求中就可以获取当前登录用户的信息,不需要再去状态服务器中获取,因此程序的运行效率更高。虽然用户信息保存在客户端,但是由于有签名的存在,客户端无法篡改这些用户信息,因此可以保证客户端提交的JWT的可信度。
安装NuGet包
Install-Package Microsoft.IdentityModel.Tokens
Install-Package System.IdentityModel.Tokens.Jwt
Jwt辅助类(生成令牌,解码令牌)
public class JwtHelper
{
private string _SecurityKey;//秘钥 注意:密钥长度需要大于16位
private string _Issuer;//jwt签发者
private string _Audience;//接收jwt的一方
private int _Expires;//jwt的过期时间,这个过期时间必须要大于签发时间
public JwtHelper()
{
_SecurityKey = "1234567890123456";
_Expires = 3600;
}
/// <summary>
/// 根据账号密码生成 Token
/// </summary>
public string GetToken(string loginName, string loginPassword)
{
#region 有效载荷, 可以自己写,爱写多少写多少;尽量避免敏感信息
var cls = new[]
{
new Claim("loginName",loginName),
new Claim("loginPassword",loginPassword),
};
#endregion
//加密
//依赖Nuget:Microsoft.IdentityModel.Tokens
SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_SecurityKey));
//签名
SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
//依赖Nuget:System.IdentityModel.Tokens.Jwt
var jwtSecurityToken = new JwtSecurityToken(
issuer: _Issuer,//jwt签发者
audience: _Audience,//接收jwt的一方
notBefore: DateTime.Now,//定义在什么时间之前,该jwt都是不可用的
expires: DateTime.Now.AddSeconds(_Expires),//jwt的过期时间,这个过期时间必须要大于签发时间
claims: cls,
signingCredentials: creds
);
var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
return token;
}
/// <summary>
/// 对jwt字符串 解码
/// </summary>
public Dictionary<string, string> DecodeJwt(string jwtStr)
{
Dictionary<string, string> dic = new Dictionary<string, string>();
var jwtHandler = new JwtSecurityTokenHandler();
// token校验
if (!string.IsNullOrEmpty(jwtStr) && jwtHandler.CanReadToken(jwtStr))
{
JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
var claims = jwtToken.Claims;
foreach (var claim in claims)
{
dic.Add(claim.Type, claim.Value);
}
}
return dic;
}
}
Program.cs
JwtHelper jwtHelper = new JwtHelper();
//生成JWT令牌
var jwtToken = jwtHelper.GetToken("demo", "123456");
Console.WriteLine(jwtToken);
//解码JWT令牌
var dic = jwtHelper.DecodeJwt(jwtToken);
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(dic));