JWT概览

是什么?

我一般学习新技术都很喜欢官方文档做的简洁明了的,JWT就是,JWT的官网就做的十分好, 第一眼你想知道的就摆在了你的眼前:
JWT是 JSON(不懂什么是JSON的可以翻翻我之前写的文章: 傻傻弄不清楚的JSON?) WEB Token(令牌)的缩写, 所以按字面意思我们就可以将JWT理解为WEB中JSON形式的令牌,这个令牌你可以理解为通行证,进入系统的令牌。

Although JWTs can be encrypted to also provide secrecy between parties, we will focus on signed tokens. Signed tokens can verify the integrity of the claims contained within it, while encrypted tokens hide those claims from other parties. When tokens are signed using public/private key pairs, the signature also certifies that only the party holding the private key is the one that signed it.
尽管JWT因为被加密从而为两个安全实体之间交换信息提供安全性,我们还是将注意力放在被签名的token上。拥有签名的token(或者被签名的token)可以验证包含在其中的信息的完整性。加密过的token也隐藏了来源方的信息。当令牌所使用的签名方式持有公钥或者私钥时,签名也可以证实持有私钥的是对token进行签名的那一方。

RFC 是什么?

RFC是Request for Comments的缩写,翻译的话可以理解为征求意见稿,互联网存在一系列的标准和协议,比如HTTP、TCP等,那这些协议和标准由谁来推进或者更新呢? 就是由互联网工程任务组(IETF)来推进和更新的,RFC就像是一份征求意见稿一样,每份网络协议的更新都会有对应的RFC,由IETF审核通过之后,予以推行。1996年3月,清华大学提交的适应不同国家和地区中文编码的汉字统一传输标准被IETF通过为RFC 1922,成为中国大陆第一个被认可为RFC文件的提交协议。

可以用来干什么?

  • Authorization: This is the most common scenario for using JWT. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. Single Sign On is a feature that widely uses JWT nowadays, because of its small overhead and its ability to be easily used across different domains.

  • Information Exchange: JSON Web Tokens are a good way of securely transmitting information between parties. Because JWTs can be signed—for example, using public/private key pairs—you can be sure the senders are who they say they are. Additionally, as the signature is calculated using the header and the payload, you can also verify that the content hasn't been tampered with.

JWT的组成

header

这个payload我们姑且可以理解为请求体,携带所要了所要交换的信息,header携带的信息为加密方式,本身也用Base64URL进行加密。JWT的三部分之间由.来进行分割,典型的JWT组成像下面这样:

典型的header组成:

{
  "alg": "HS256",
  "typ": "JWT"
}

claims

The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically, the user) and additional data. There are three types of claims: registered, public, and private claims.
Payload中携带了交换的信息,这些交换的信息在声明中, 交换的信息一般是实体(典型的就是用户)和一些额外的数据,有三种类型的声明:

  • Registered claims(已经定义过的声明): These are a set of predefined claims which are not mandatory but recommended, to provide a set of useful, interoperable claims. Some of them are: iss (issuer), exp (expiration time), sub (subject), aud (audience), and others.

  • Public claims

  • Private claims:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

signature

To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that .For example if you want to use the HMAC SHA256 algorithm, the signature will be created in the following way:
创建签名部分你需要将header和payload、secret按照请求头中的加密算法进行编码。下面是一个使用HMAC SHA256算法创建签名的典型例子:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

The signature is used to verify the message wasn't changed along the way, and, in the case of tokens signed with a private key, it can also verify that the sender of the JWT is who it says it is.

怎么用?

我们现在来尝试使用一下JWT,首先我们去maven私服,去找下对应jar包:

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.18.1</version>
</dependency>

生成JWT并解析JWT

public class Test {
    public static void main(String[] args) {
        String  str = makeToken();
        parseToken(str);
    }

    private static void parseToken(String str) {
        // 放入签发的密钥,对JWT进行解密
        Jwt info = Jwts.parser().setSigningKey("changanbujian").parse(str);
        System.out.println(info);
    }

    private static String makeToken() {
        Map<String,Object> header = new HashMap<>();
        header.put("alg","HS256");
        header.put("typ","JWT");
        Claims claims = new DefaultClaims();
        claims.setId("ccc").setSubject("aaa").setIssuer("bbb").setExpiration(new Date(System.currentTimeMillis() + 1800 * 1000));
        String secret = "changanbujian";
        // 上面讲过JWT需要Base64的形式
        byte[] saltBase64 = DatatypeConverter.parseBase64Binary(secret);
        SignatureAlgorithm hs256 = SignatureAlgorithm.HS256;
        SecretKeySpec secretKeySpec = new SecretKeySpec(saltBase64,hs256.getJcaName());
        String jwtToken = Jwts.builder().setHeader(header).setClaims(claims).signWith(hs256, secretKeySpec).compact();
        return jwtToken;
    }
}

总结一下

JWT 是 JSON WEB TOKEN的缩写,是令牌的一种形式,有三部分组成:

  • header

  • payload

  • signature

实际使用中我们常常会对在原来的JWT的基础上再进行加密,加密和解密方式对的上,才能从密文中解析出来信息。

参考资料

  • JWT文档翻译中英对照 -- introduction
  • JWT 官网
03-05 15:21