头图

JWT学习笔记(一)

北冥有只鱼
English
这周在做单点登录,这次的单点登录解析用户信息是JWT中解析用户信息,但是第三方给的从JWT中解析用户信息的文档中提供解析token的方式解不出来,我当时心态就有点崩,后来自己查了一些资料才发现第三方给的从JWT中解析用户信息的方式是有问题的,但是我一想还是对JWT还不大了解,于是打算系统的学一下JWT。

JWT概览

是什么?

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

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object.

JWT 是一种被开放规范RFC-7519所定义的一种在不同安全实体使用JSON安全传输数据的一种(紧凑而又自包含)方法(或者方式)。

his information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

因为JWT带有数字签名,所以使用JWT传输的信息是可以验证和信任的。电子签名可以使用HMAC算法或者使用RSA、ECDSA非对称加密的公钥、私钥来实现。

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.

    鉴权: 这是JWT最常见的使用场景,只要用户一次成功登陆,之后的每次请求携带JWT,就能够访问这个JWT所被允许的访问的一切(我们可以理解为JWT是一个类似于身份证的存在,服务端从请求中拿到JWT就能够知道当前登录用户是谁以及所允许的访问的资源)。当今,单点登录广泛使用JWT实现,因为开销小,并且能够在很容易不同的安全实体中所使用。
  • 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是一个在不同实体中安全交换信息的良好实现, 因为JWT的签名,比如使用非对称加密,你就可以确信发送者的身份(防止第三方假冒),签名是通过JWT的header和payload计算得来。你可以通过这个来验证这些信息有没有被修改过

JWT的组成

header

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

xxxxx.yyyyy.zzzzz

典型的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.

    这些声明是预定义字段是非强制但是推荐的,用于提供一组有效的声明。一些典型的,比如iss(发行者)、exp(过期时间)、sub(Subject 主体)等等 ,为什么都是缩写? 因为JWT要求紧凑。
  • Public claims

    These can be defined at will by those using JWTs. But to avoid collisions they should be defined in the IANA JSON Web Token Registry or be defined as a URI that contains a collision resistant namespace.
    这些可以由使用JWTs的人自定义,但是为了避免冲突,在定义之后在IANA JSON Web Token Registry注册一下,或者在被定义在URI可以避免冲突。
  • Private claims:

    These are the custom claims created to share information between parties that agree on using them and are neither registered or public claims.
    这是信息交换双方统一交换信息的声明,不应当被注册或者发布在公共声明里面。
    我们可以将声明理解为字段,Registered claims理解为预定义字段,Public claims理解为大家约定的字段。Payload也用Base64进行加密。
Do note that for signed tokens this information, though protected against tampering, is readable by anyone. Do not put secret information in the payload or header elements of a JWT unless it is encrypted.
如果信息没有被加密,那么不建议在payload中放入机密信息,尽管这些信息可以被签名保护,不被篡改,但任何人都可以阅读到。
payload示例:
{
  "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

    根据header和payload生成,防止被篡改,也确认发送者的身份。

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

参考资料

  • JWT文档翻译中英对照 -- introduction
  • JWT 官网
阅读 1.1k
25 声望
11 粉丝
0 条评论
25 声望
11 粉丝
文章目录
宣传栏