JWT(JSON Web Token), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准,该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
Header:base64编码的Json字符串
Payload:base64编码的Json字符串
Signature:使用指定算法,通过Header和Payload加盐计算的字符串
header
jwt的头部承载两部分信息:
{
//声明类型
'typ': 'JWT',
//签名加密的算法
'alg': 'RS256'
}
playload
载荷就是存放有效信息的地方,比如用户名密码等登录信息
signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成
// 根据头部alg算法与私有秘钥进行加密得到的签名字符串;
// 这一段是最重要的敏感信息,只能在服务端解密;
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
SECREATE_KEY
)
这个部分需要base64加密后的header和base64加密后的payload使用 “.” 连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
将这三部分用"."连接成一个完整的字符串,构成了最终的jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥。
加密
生成头JSON,荷载(playload) JSON
将头JSON Base64编码 + 荷载JSON Base64编码 +secret 三者拼接进行加密得到签名
JSON Base64编码 + 荷载JSON Base64编码 + 签名 三者通过 “.” 相连接
一条 hhh.ppp.sss 格式的JWT 即生成
解密
取得Jwt hhh.ppp.sss 格式字符,通过 “.” 将字符分为三段
对第一段进行Base64解析得到header json,获取加密算法类型
将第一段Header JSON Base64编码 + 第二段 荷载JSON Base64编码 + secret采用相应的加密算法加密得到签名
将步骤三得到的签名与步骤一分成的第三段也就是客户端传入的签名进行匹配,匹配成功说明该jwt为server自身产出;
获取playload内信息,通过信息可以做鉴权操作;
无状态登录
微服务集群中的每个服务,对外提供的都是Rest风格的接口,而Rest风格的一个最重要的规范就是:服务的无状态性, 即:
服务端不保存任何客户端请求者状态信息
客户端的每次请求必须具备自描述信息, 通过这些信息识别客户端身份
优点:
客户端请求不依赖服务端的信息, 任何多次请求不需要必须访问到同一台服务
服务端的集群和状态对客户端透明
服务端可以任意的迁移和伸缩
减小服务端存储压力
JJwt是Java对jwt的支持库,使用该库创建解析token
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.9.0version>
dependency>
客户端发送 POST 请求到服务器,提交登录处理的Controller层,调用认证服务进行用户名密码认证,如果认证通过,返回完整的用户信息及对应权限信息,利用 JJWT 对用户、权限信息、秘钥构建Token,返回构建好的Token。
/**
* 私钥加密生成token
* @param user 载荷数据
* @param privateKey 私钥字节数组
* @param expireMinutes 过期时间,单位分钟
* @return
*/
public static String generateToken(ShopUser user, byte[] privateKey, Integer expireMinutes) throws Exception{
return Jwts.builder()
.claim(JWTConstants.JWT_KEY_ID, user.getId())
.