JSON WEB TOKE入门原理与实际案例测试

1.什么是JWT?

 JWT全称JSON Web Token。是为了在网络应用环境键传递声明而执行的一种基于JSON的开放标准。

2.JWT的使用场景?

  授权:一旦用户登录,每个后续请求将包括JWT,允许用户访问该令牌允许的路由,服务和资源。单点登录是一种在广泛使用JWT的功能,因为它的开销很小,并且能够在不同的域中轻松使用。

  信息交换:JSON Web令牌是在各方之间安全传输信息的好方法。因为JWT可以签名 - 例如,使用公钥/私钥对 - 您可以确定发件人是他们所说的人。此外,由于使用标头和有效负载计算签名,您还可以验证内容是否未被篡改。

3.JWT的结构组成?

  由三部分组成,用(.)进行分隔,他们是

  • 头部(header)
  • 有效载荷(payload)
  • 签名(signature)

  因此,JWT通常如下表示

  xxxxxx.yyyyy.zzzzz

  头部:

  JWT头部分是一个描述JWT元数据的JSON对象,通常如下所示

  

       在上面的代码中,alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT。然后,这个json被编码称Base64Url,形成JWT的第一部分。

  有效载荷:

  有效载荷是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。JWT指定七个默认字段供选择。

  iss:发行人

  exp:到期时间

  sup:主题

  aud:用户

  nbf:在此之前不可用

  iat:发行时间

  jti:JWT ID用于标识该JWT

  除以上默认字段外,我们还可以自定义私有字段,如下例:

  

  请注意,默认情况下JWT是未加密的,任何人都可以解读其内容,因此不要构建隐私信息字段,存放保密信息,以防止信息泄露。

  JSON对象也使用Base64 URL算法转换为字符串保存,形成JWT第二部分。

  签名:

  签名是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。

  首先,需要制定一个密钥(secret)。该密钥仅仅为保存在服务器中,并且不能向用户公开。然后,使用头部中指定的签名算法(默认情况下为HMACSHA256)根据以下公式生成签名。

  

  在计算出签名后,将JWT头部,有效载荷和签名的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象,返回给用户。

4.JWT的用法?

  JWT的原理是,服务器认证以后,生成一个JSON对象,发回给用户,如下面格式

  {
    "姓名": "张三",
    "角色": "管理员",
    "到期时间": "2018年7月1日0点0分"
  }

  以后用户与服务端通信的时候,都要返回这个JSON对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名。

  客户端收到服务器返回的JWT,可以存储到Cookie里面,也可以存储到localStorage。

  此后,客户端每次与服务器通信,都要带上这个JWT。你可以把它放在cookie里面自动发送,但是这样就不能实现跨域。所以更好的做法是放在HTTP请求的头信息Authorization字段里面

  另一种做法是,跨域的时候,JWT就放在POST请求的数据里面。

5.JWT特点?

  (1)JWT默认是不加密的,但也是可以加密的。生成原始Token以后,可以用密钥在加密一次。

  (2)JWT不加密的情况下,不能将秘密数据写入JWT。

  (3)JWT不仅可以用于认证,也可以死用于交换信息。有效使用JWT,可以降低服务器的查询数据库的次数。

  (4)JWT最大的缺点是,用于服务器不保存sessi000on状态,因此无法在使用过程中废止某个token,或者更改token的权限,也就是说,一旦JWT签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

  (5)JWT本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT的有效期限应该设置的比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

  (6)为了较少盗用,JWT不应该使用HTTP协议明码传输,要使用HTTPS协议传输。

 7.JWT的入门案例(Java方式)

   创建一个项目,先引入依赖。

 <dependency>
     <groupId>io.jsonwebtoken</groupId>
     <artifactId>jjwt</artifactId>
     <version>0.9.0</version>
 </dependency>
 <dependency>
     <groupId>com.auth0</groupId>
     <artifactId>java-jwt</artifactId>
     <version>3.2.0</version>
 </dependency>
public class TokenUtil {
    private static final String APP_KEY = "why_key"; //进行数字签名的私钥,一定要保管好,不能和我一样写到博客中。。。。。

    private TokenUtil(){

    }
    /**
     * 一个JWT实际上就是一个字符串,它由三部分组成,头部(Header)、载荷(Payload)与签名(Signature)
     * @param id 当前用户ID
     * @param issuer 该JWT的签发者,是否使用是可选的
     * @param subject 该JWT所面向的用户,是否使用是可选的
     * @param ttlMillis 什么时候过期,这里是一个Unix时间戳,是否使用是可选的
     * @param audience 接收该JWT的一方,是否使用是可选的
     * @return
     */
    public static String createJWT(String id,String issuer,String subject,long ttlMillis, String audience){
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(APP_KEY);

        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());

        JwtBuilder jwtBuilder = Jwts.builder()
                .setId(id)
                .setSubject(subject)
                .setIssuedAt(now)
                .setIssuer(issuer)
                .setAudience(audience)
                .claim("name","自定义字段")
                .signWith(signatureAlgorithm,signingKey);
        //设置Token的过期时间
        if(ttlMillis >=0){
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            jwtBuilder.setExpiration(exp);
        }

        return jwtBuilder.compact();

    }

    //私钥解密token信息
    public static Claims getClaims(String jwt) {
        return Jwts.parser()
                .setSigningKey(DatatypeConverter.parseBase64Binary(APP_KEY))
                .parseClaimsJws(jwt).getBody();
    }

}

编写一个Test类来测试一下

public class JsonWebTokenTest {
    @Test
    public void jsonTest(){
        String userId = "xyzjidgdgd";
        String issuer = "https://baidu.com";
        String subject = "技术部";
        long ttlMillis = 1000 * 60;
        String audience = "技术部测试";
        String token = TokenUtil.createJWT(userId,issuer,subject,ttlMillis,audience);
        //打印出token信息
        System.out.println(token);


//        解密token信息
        Claims claims = TokenUtil.getClaims(token);
        System.out.println("---------------------------解密的token信息----------------------------------");
        System.out.println("ID: " + claims.getId());
        System.out.println("Subject: " + claims.getSubject());
        System.out.println("Issuer: " + claims.getIssuer());
        System.out.println("Expiration: " + claims.getExpiration());
        //自定义字段的获取方式有所不同
        System.out.println("Expiration: " + claims.get("name", String.class));
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章