Token:身份验证的令牌
当用户尝试登录,将请求提交到服务器端,如果服务器端认证通过,会生成一个Token数据并响应到客户端,此Token是有意义的数据,此客户端在后续的每一次请求中,都应该携带此Token数据,服务器端通过解析此Token来识别用户身份!
关于Session与Token:
- Session默认是保存在服务器的内存中的数据,会占用一定的服务器内存资源,过期时间短,并且不适合集群或分布式系统(虽然可以通过共享Session来解决),客户携带的Session ID只具有唯一性的特点(理论上),不具备数据含义
- Token的本质是将有意义的数据进行加密处理后的结果,各服务器都只需要具有解析这个加密数据的功能即可获取到其中的信息含义,理论上不占用内存资源,过期时间允许长,更适用于集群和分布式系统,但是,存在一定的被解密的风险(概率极低)
JWT
JSON Web Token,是使用JSON格式表示多项数据的Token. 它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证JWTToken的正确性,只要正确即通过验证。在使用JWT之前,需要在项目中添加相关的依赖,用于生成JWT和解析JWT
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
一个原始的JWT数据应该包含3个部分:
1.Head头部:ALGORITHM&TOKEN TYPE(算法与Token类型)
{
"alg": "HS256",
"typ": "JWT"
}
2.PAYLOAD(载荷):DATA 此部分的数据是自定义,可按需存入任何所需的数据。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)
3.VERIFY SIGNATURE(验证签名)
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)
JWT生成
Map<String, Object> claims = new HashMap<>();
claims.put("id", 9527);
claims.put("name", "LiuLaoShi");
claims.put("nickname", "JavaCangLaoShi");
// JWT的过期时间
Date expiration = new Date(System.currentTimeMillis() + 5 * 60 * 1000);
System.out.println("过期时间:" + expiration);
// JWT的组成:Header(头:算法和Token类型)、Payload(载荷)、Signature(签名)
String jwt = Jwts.builder()
// Header
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
// Payload
.setClaims(claims)
.setExpiration(expiration)
// Signature
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
System.out.println("JWT=" + jwt);
JWT解析
// 注意:必须使用相同secretKey生成的JWT,否则会解析失败
// 注意:不可以使用过期的JWT,否则会解析失败
// 注意:复制粘贴此JWT时,不要带“尾巴”,否则会解析失败
// 注意:不可以恶意修改JWT中的任何字符,否则会解析失败
String jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiTGl1TGFvU2hpIiwibmlja25hbWUiOiJKYXZhQ2FuZ0xhb1NoaSIsImlkIjo5NTI3LCJleHAiOjE2NjI0NTY3ODN9.32MwkSbDz1ce4EvEKHFMCIjcQFUDZz6hn5MtAYr0njQ";
Claims claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody();
Integer id = claims.get("id", Integer.class);
String name = claims.get("name", String.class);
String nickname = claims.get("nickname", String.class);
System.out.println("id = " + id);
System.out.println("name = " + name);
System.out.println("nickname = " + nickname);
JWT实现微服务架构下的SSO
FAQ
1.JWT授权流程和鉴权流程:
- 授权流程
1、用户请求登录,携带用户名密码到授权中心
2、授权中心携带用户名密码,到用户中心查询用户
3、查询如果正确,生成JWT凭证
4、返回JWT给用户 - 鉴权流程:
1、用户请求某微服务功能,携带JWT
2、微服务将jwt交给授权中心校验
3、授权中心返回校验结果到微服务
4、微服务判断校验结果,成功或失败
5、失败则直接返回401
6、成功则处理业务并返回
2.JWT相比传统token的优势?
传统的token: 客户端请求来的token,必选先找到存贮这个token的服务器是那台,然后由那一台服务器进行用户身份验证
JWT: 只需要每一台服务器都知道解密密钥,那么每一台服务器都有验证用户身份的能力