spring cloud学习笔记 JWT令牌
在微服务框架中,用户信息是个很头疼的问题。首先为了实现单点登录,用户在一个系统登录后,就无需在其他系统再进行登录,那么用户信息就需要在第一次登录后进行存储到cookie,那么当我们在cookie中获取用户信息时,该如何验证用户信息没有被篡改?其次用户信息都是敏感数据,如果明文展示势必会造成隐私泄露。为了解决这些问题,就有必要学习JWT令牌。
一、JWT介绍
JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。JWT一共有三部分组成,分别是:头部、载荷、签证。
1.头部(Header)
头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。它是一个JSON字符串,如下例子:
{ "typ":"JWT",//类型 "alg":"HS256"//算法 }
2.载荷(playload)
载荷就是存放用户信息、和有效数据的地方。它一共有三个部分组成
(1)标准中注册的声明
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
(2)公共的声明
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息,但不建议添加敏感信息,因为该部分在客户端可解密。
(3)私有的声明
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息。这个指的自定义的信息,这些信息跟JWT标准规定的信息区别在于:JWT规定的信息,JWT的接收方在拿到JWT之后,都知道怎么对这些标准的信息进行验证(还不知道是否能够验证);而私有的信息不会验证,除非明确告诉接收方要对这些信息进行验证以及规则才行。如下例子:
{ "iss":"xiaoming", //标准声明 "name":"xiaowang", //私有声明 "age":10//私有声明 }
3.签证
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
Header通过Base64加密的字符串 + playload通过Base64加密的字符串 + 秘钥
完整的字符串如下:
eyJhbGciJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZ6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.VA95OrM7E2cBab3MHrcEfxjoYZgeFONFh7HgQ
需要注意的是,秘钥是保存在服务端的,令牌签发也是在服务端,因此秘钥只能在服务器中,不能泄露出去,否则客户端能自己进行签发令牌。
最重要的是签证的作用就是用来验证数据是否被进行了修改,根据签证生成规则可以看到,如果载荷中的信息被修改了,那么生成的字符串和签发的令牌一定是不相同的。
二、JWT的使用
1.引入maven
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency>
2.令牌签发、解析实例
public static void main(String[] args) { String jwt=createJwt(); System.out.println("签发的令牌:"+jwt); Claims claims=parseJwt(jwt); String jsonStr= JSON.toJSONString(claims); System.out.println(jsonStr); } /** * 签发令牌 * @return */ public static String createJwt(){ JwtBuilder builder= Jwts.builder() .setId(UUID.randomUUID().toString().replace("-","")) //设置唯一编号 .setSubject("测试主题") //设置发送的主题 .setExpiration(new Date()) //设置过期时间 .setIssuedAt(new Date()) //设置签发日期 .signWith(SignatureAlgorithm.HS256,"abc");//设置签名 使用HS256算法,abc为私钥 //设置用户信息 Map<String,Object> map=new HashMap<>(); map.put("name","小明"); map.put("age",25); builder.addClaims(map); //构建 并返回一个字符串 return builder.compact() ; } /** * 解析令牌 * @param jwt * @return */ public static Claims parseJwt(String jwt){ Claims claims = Jwts.parser(). setSigningKey("abc").//设置私钥 parseClaimsJws(jwt). getBody(); return claims; }