Oauth2系列8:何谓JWT令牌?

传送门

Oauth2系列1:初识Oauth2

Oauth2系列2:授权码模式

Oauth2系列3:接入前准备

Oauth2系列4:密码模式

Oauth2系列5:客户端凭据模式

Oauth2系列6:隐式模式

Oauth2系列7:授权码和访问令牌的颁发流程是怎样实现的?

什么是JWT令牌

官方网站地址:JSON Web Tokens - jwt.io

如果接触过jwt,可能没有看过这个网址,但是应该见过下面这个图(很多网上的文章都会引用);这个地址是用来解析jwt_token结构体的工具

所以,就正式来看下官方给的定义:

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

翻译过来大致就是

 JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。

从上面可以看到jwt令牌定义成3部分:HEADER,PAYLOAD,VERIFY SIGNATURE,它是怎么划分的呢?贴下官网的例子

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

从这个字符串可以看到,一个jwt令牌分为3段,用.分隔,按照HEADER,PAYLOAD,VERIFY SIGNATURE顺序拼接的

HEADER

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

表示装载令牌类型和算法等信息,是 JWT 的头部。其中,typ 表示第二部分 PAYLOAD 是 JWT 类型,alg 表示使用 HS256 对称签名的算法

PAYLOAD

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

表示是 JWT 的数据体,代表了一组数据。其中,sub(令牌的主体,一般设为资源拥有者的唯一标识)、iat(令牌颁发的时间戳)是 JWT 规范性的声明,代表的是常规性操作。除了这几个之外,还可以定义:

  • exp(令牌的过期时间戳)
  • iss(令牌签发者)
  • aud(令牌接收者)

更多的细节可以在JSON Web Token (JWT)查看

不过,在一个 JWT 内可以包含一切合法的 JSON 格式的数据,也就是说,PAYLOAD 表示的一组数据允许我们自定义声明。 比如:name(用户名称)。因为PAYLOAD里面往往是填充的业务数据,所以可以不局限于上面的几个标准字段。而且通常业务系统是会直接从这里获取数据的,所以有些字段是双方约定好的带有业务含义的,比如"age","birthday"等等。

VERIFY SIGNATURE

表示对 JWT 信息的签名。那么,它有什么作用呢?其实就是做验签:需要对其进行加密签名处理,而 SIGNATURE 就是对信息的签名结果,当受保护资源接收到第三方软件的签名后需要验证令牌的签名是否合法。我们可能认为,有了 HEADER 和 PAYLOAD 两部分内容后,就可以让令牌携带信息了,似乎就可以在网络中传输了,但是在网络中传输这样的信息体是不安全的,因为你在“裸奔”。

JWT令牌更像是一种协议

虽然名字叫jwt令牌,其它感觉把它作为一种协议感觉理合理些。

就是jwt跟oauth2是同一级别的,都是可以用于授权!

那么为什么有了oauth这种成熟且强大的授权协议,还会出现jwt呢?

回顾一下前面的Oauth2系列7:授权码和访问令牌的颁发流程是怎样实现的?

 里面提到了令牌的生成及使用:一般的令牌格式是一个字符串,对于它没有什么格式化的要求;而且客户端拿到令牌之后,需要获取其它资源信息,需要通过token到资源服务器去再次获取。

就是说:

  • 令牌的存储它是在授权服务器,客户端只拿到一个token的字符串标识,是不知道token背后具体的业务数据的
  • 所有需要的业务数据,必须通过token到授权服务器再次换取

那么,有没有一种方式,让用户拿到token之后,直接获取业务数据呢?这样授权流程更简单,也没有了授权服务器存储的要求,为此JWT应运而生!

JWT令牌的使用场景

在刚才的官网下面有一个警告提示,也反应了它的使用场景:

  • jwt令牌是一种凭据,可用于资源授权
  • 同oauth2一样,令牌是需要保护的,防止泄露
  • 令牌不会存储,在客户端进行验证

至此,JWT的应用场景呼之欲出,可以单独用做授权,也可以做为oauth2的令牌发放!

利用jwt可以带来几个好处:

  • 因为jwt本身是结构化生成的,包含业务数据,所以避免了额外的存储及一些系统交互,有点类似时间换空间的思想(因为客户端要解析jwt令牌,是通过算法计算,会消耗时间)。
  • 可以提高系统的伸缩性,因为jwt令牌不用存储,在分布式系统下,如果用它做会话管理,就天然无状态的;并且从授权服务器的角度,因为不用存储及交互,也减轻了它的压力,都分摊到客户端去了
  • 再一个就是jwt本身的保密性,因为里面要求验签,也不用做额外的安全处理

但是,肯定是有它的局限性:

  • jwt令牌一旦发放,是无法撤销的。虽然在jwt令牌的PAYLOAD里面设置exp(令牌的过期时间戳),但是无论多短,在未过期之前,该令牌都无法主动让它失效。一旦发生泄露,将没有任何补救措施。
  • 基于上,这也是有些场景用jwt令牌做登录,登录成功发放jwt令牌,但是如果用户主动退出,是没有办法做的,只能用类似黑名单的方式记录下这些令牌,但是这又退化到oauh令牌了,违背了设计的初衷

JWT令牌的实现

 官方网站地址:JSON Web Token Libraries - jwt.io

提供了不同语言,不同的实现

找一个JAVA版本的jjwt来试试

安装maven依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

生成令牌

public static void main(String[] args)
    {
        // 生成jwt令牌
        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        String jwtToken = Jwts.builder().setSubject("Joe").signWith(key).compact();

        // 检验jwt令牌
        String name = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(jwtToken).getBody().getSubject();
        System.out.println("subject:" + name);
    }

直接用jjwt库完成jwt令牌的生成与检验很简单。一般来说,生成是在授权服务器,也就是

// 生成jwt令牌
        Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        String jwtToken = Jwts.builder().setSubject("Joe").signWith(key).compact();

而检验一般是客户端里面实现的,即

// 检验jwt令牌
        String name = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(jwtToken).getBody().getSubject();

这样,就涉及密钥,即上面的Key,这个理论上是授权服务器颁发,下发给客户端,需要加密传输。即生成+检验要用同样的Key

令牌格式

打印一下刚才生成的token:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.u3U3CnkpdJyPqmwcrLt50yxozKVupV-piuVHpWqwPqw 

可以发现明显的分为3段,用.分隔,并且将它放到jwt的工具网站里面

 可以直观的看到完整的数据结构了!

对称加密

JJwt也支持公/私钥这种密钥对的方式,如下

// 密钥对
        KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);
        // 私钥加密
        String jwtToken2 = Jwts.builder().setSubject("James").signWith(keyPair.getPrivate()).compact();

        // 检验jwt令牌,公钥解密
        String name2 = Jwts.parserBuilder().setSigningKey(keyPair.getPublic()).build().parseClaimsJws(jwtToken2).getBody().getSubject();
        System.out.println("subject:" + name2);
  • Keys.keyPairFor(SignatureAlgorithm.RS256),工具方法生成密钥对
  • 私钥加密
  • 公钥解密 

同上操作,打印一下刚才生成的token:

eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJKYW1lcyJ9.ZfiWiXCcmYBtskj_zZrxsPD8_4-ADQGd2C6Sn1lsTE-47eg6a2jY8H_uc8BPJ8AQXwHYxGw75EOir8tco4Q3xVXHXaRxMcuLsp7B4HULc6CujwRjCvFJhyBe2IjADHWVWRgQ4zKOsmX2poUQnOiQ5BgBVR2GUbxcSCEZ5L649jc43mJHHyuzPs6IMUOhqzpliAcxVg5Fh-AtVsxneYWYks9wXlRIqYarGxtgR5LgSrGs3fTfALMZy-qYsSjHm0VaBg9vSOWmSfgne8xVdsy2Z6FF7K9RNES1e5_XKaY6k0vfPvVnYDMIlOW6BAgbxHclgiEy43vHbNglaM4mIcoh7Q

 

令牌检验

如果Key错误,理论上是通过异常的方式,把上面例子的key在检验之前,随便修改一下运行

Exception in thread "main" io.jsonwebtoken.security.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:399)
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:529)
	at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:589)
	at io.jsonwebtoken.impl.ImmutableJwtParser.parseClaimsJws(ImmutableJwtParser.java:173)
	at com.tw.tsm.jwt.JjwtDemo.main(JjwtDemo.java:19)

如果抛出这个异常SignatureException就表示,jwt令牌不合法 

更多的用法可以研究API

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot Security OAuth2是基于Spring Security和OAuth2的框架,用于实现授权服务器和资源服务器。JWT令牌是一个基于JSON的开放标准,用于在各方之间安全地传输信息。 在Spring Boot Security OAuth2中实现支持JWT令牌的授权服务器,可以按照以下步骤进行: 1. 添加依赖:在项目的pom.xml文件中添加Spring Security OAuth2和JWT的相关依赖。 2. 配置授权服务器:在Spring Boot应用程序的配置文件中,配置授权服务器的基本设置,包括端点URL、客户端信息、用户认证信息等。 3. 配置JWT令牌:配置JWT令牌的签名密钥和过期时间等信息。可以使用开源库如jjwt来生成和验证JWT令牌。 4. 创建自定义的认证提供程序:实现自定义的认证提供程序来支持JWT令牌的认证机制。在认证提供程序中,可以使用JWT令牌解析并验证请求中的令牌信息。 5. 创建自定义的用户详细信息服务:实现自定义的用户详细信息服务,用于从数据库或其他存储中获取用户的详细信息。在用户详细信息服务中,可以根据JWT令牌中的信息获取用户信息。 6. 配置授权服务器的访问规则:配置授权服务器的访问规则,包括允许或禁止特定角色或权限的访问。 7. 测试访问授权服务器:使用客户端应用程序发送请求到授权服务器的端点,获取JWT令牌并验证其有效性。 通过以上步骤,可以实现一个支持JWT令牌的授权服务器。该服务器可以提供为客户端应用程序颁发和验证JWT令牌的功能,以实现安全并可靠的用户认证和授权控制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值