JWT详情和如何使用

1、什么是JWT?

JSON Web Token (JWT)是一个开放的行业标准(RFC 7519),它定义了一种简洁的、自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或使用RSA的公钥/私钥对进行签名,防止被篡改。

JWT令牌的优点:

  • JWT基于json,非常方便解析。

  • 可以在令牌中自定义丰富的内容,易扩展。

  • 通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高。

  • 资源服务使用JWT可不依赖认证服务即完成授权。

JWT令牌的缺点:

JWT令牌较长,占存储空间比较大 

 2、JWT组成

一个JWT实际上就一个字符串,它由三部分组成,头部、负载与签名。

 1、头部(Header)

头部用于描述关于该JWT的最基本信息,例如其类型(即JWT)以及签名所用的算法(如HMAC SHA256 或 RSA)等。这也可以被表示成一个JSON对象。

JSON字符串

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

  • alg:签名算法

  • typ:类型

我们对头部的json字符串进行BASE64编码,编码后的字符串如下:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 

Base64是一种基于64个可打印字符串来表示二进制数据的表示方式。JDK提供了非常方便的Base64Encoder和Base64Decoder,用它们可以非常方便的完成基于Base64的编码和解码。  

2、负载(Payload)  

负载,是存放有效信息的地方,比如用户的基本信息可以存在该部分中。负载包含三个部分:

  • 标准中注册的声明(建议但不强制使用)

    • iss:jwt签发者

    • sub:jwt所面向的用户

    • aud:接收jwt的一方

    • exp:jwt的过期时间,过期时间必须大于签发时间

    • nbf:定义在什么时间之前,该jwt都是不可用的

    • iat:jwt的签发时间

    • jti:jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

  • 公共的声明

公共的声明可以添加任何信息,一般添加用户的相关信息或其他业务需要的必要信息,但不建议添加敏感信息,因为该部分在客户端可解密。

  • 私有的声明

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

私有声明也就是自定义claim,用于存放自定义键值对

 Json字符串

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

 其中sub是标准的声明,name是自定义的私有声明,编码后如下:

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

3、签证、签名(Signature)

jwt的第三部分是一个签证信息,由三部分组成:

  • Header(Base64编码后)

  • Payload(Base64编码后)

  • Secret(盐,必须保密)

这个部分需要Base64加密后的header和base4加密后的payload使用.连接组成的字符串,然后通过header重声明的加密方式进行加盐Secret组合加密,然后就构成了JWT的第三部分——使用“qfjava”作为盐:

eZqdTo1mRMB-o7co1oAiTvNvumfCkt-1H-CdfNm78Cw

三个部分组合出的完整字符串:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.eZqdTo1mRMB-o7co1oAiTvNvumfCkt-1H-CdfNm78Cw

 注意:secret是保存在服务器端的,jwt在签发生成也是在服务器端的,secret就是用来进行jwt的签发和验证,所以,它就是服务器端的私钥,在任何场景都不应该泄漏。一旦客户端得知这个secret,那就意味着客户端是可以自我签发jwt了。

3、Token与·JWT 

3.1 token与JWT

token是一个很宽泛的概念,翻译为令牌,一般用来表示经过验证之后得到的凭证,长度没有什么限制,多长都可以。

jwt是 JSON Web Token,它也自称是一种token,jwt就是一个很具体的标准了,用点号分为三段,分别表示头、信息和签名。token有很多种,可以是标准的,也可以是你自己定义的,jwt则是其中一种token,而且是标准的token。和我们自己随意定义的token差别大是很自然的,因为我们自己定义的token只需要用来识别用户登录状态,一般很短的uuid都可以实现,所以比较短。

4.使用JJWT

JJWT是一个提供端到端的JWT创建和验证的开源Java库。也就是说使用JJWT能快速完成JWT的功能开发。

4.1、引入依赖

创建Springboot工程并引入jjwt依赖,pom.xml如下:

        <!--jjwt-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>RELEASE</version>
        </dependency>

4.2、创建Token

//定义token时效和签名
    private long expiration = 60 * 60 * 24 * 1000;
    private String signature = "admin";

    @Test
    public void t1() {
        JwtBuilder jwtBuilder = Jwts.builder();
        String jwtToken = jwtBuilder
                //header
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                //payload
                .claim("username", "cinco")//自定义载荷
                .claim("role", "admin")//自定义载荷
                .setSubject("admin-test")
                .setExpiration(new Date(System.currentTimeMillis() + expiration))//过期时间
                .setId("1001")
                //signature
                .signWith(SignatureAlgorithm.HS256, signature)
                .compact();

        System.out.println(jwtToken);
    }

4.3、JWT将用户信息转换成Token字符串,生成结果如下:

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMDAxIiwic3ViIjoi5bCP5piOIiwiaWF0IjoxNjE1MzY2MDEyfQ.2LNcw1v64TNQ96eCpWKvtAccBUA-cEVMDyJNMef-zu0

4.4、解析Token

通过JWT解析Token,获取Token中存放的用户信息,即生成Claims对象。

@Test
    public void testParseToken() {
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImNpbmNvIiwicm9sZSI6ImFkbWluIiwic3ViIjoiYWRtaW4tdGVzdCIsImV4cCI6MTY4NjIyMDM4NiwianRpIjoiMTAwMSJ9.TfWVd8cMZx3CP09WY35LagV6s6HS2WKXpH83iFJrzQE";
        //解析Token,生成Claims对象,Token中存放的用户信息解析到了claims对象中
        Claims claims = Jwts.parser()
                .setSigningKey(signature)
                .parseClaimsJws(token)
                .getBody();

        System.out.println(claims);
        System.out.println(claims.get("username"));
        System.out.println(claims.get("role"));
        System.out.println(claims.getId());
        System.out.println(claims.getSubject());
        System.out.println(claims.getExpiration());

    }

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心对元&鑫鑫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值