推广 热搜: page  音视频  使用  个数  选择  搜索引擎  父亲  百度  企业  可以 

什么是 JWT?它是如何工作的?

   日期:2025-01-28     作者:8y2ex    caijiyuan   评论:0    移动:http://ww.kub2b.com/mobile/news/20985.html
核心提示:松哥最近辅导了几个小伙伴秋招,有小伙伴在面小红书时遇到这个问题,这个问题想回答全面还是有些挑战,松哥结

松哥最近辅导了几个小伙伴秋招,有小伙伴在面小红书时遇到这个问题,这个问题想回答全面还是有些挑战,松哥结合之前的一篇旧文和大伙一起来聊聊。

有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如 Tomcat 中的 Session。例如登录:用户登录后,我们把用户的信息保存在服务端 session 中,并且给用户一个 cookie 值,记录对应的 session,然后下次请求,用户携带 cookie 值来(这一步有浏览器自动完成,我们就能识别到对应 session,从而找到用户的信息。这种方式目前来看最方便,但是也有一些缺陷,如下

  • 服务端保存大量数据,增加服务端压力
  • 服务端保存用户状态,不支持集群化部署

微服务集群中的每个服务,对外提供的都使用 RESTful 风格的接口。而 RESTful 风格的一个最重要的规范就是:服务的无状态性,即

  • 服务端不保存任何客户端请求者信息
  • 客户端的每次请求必须具备自描述信息,通过这些信息识别客户端身份

那么这种无状态性有哪些好处呢

  • 客户端请求不依赖服务端的信息,多次请求不需要必须访问到同一台服务器
  • 服务端的集群和状态对客户端透明
  • 服务端可以任意的迁移和伸缩(可以方便的进行集群化部署
  • 减小服务端存储压力

无状态登录的流程

  • 首先客户端发送账户名/密码到服务端进行认证
  • 认证通过后,服务端将用户信息加密并且编码成一个 token(一般是 JWT,返回给客户端
  • 以后客户端每次发送请求,都需要携带认证的 token
  • 服务端对客户端发送来的 token 进行解密,判断是否有效,并且获取用户登录信息

JWT,全称是 Json Web Token, 是一种 JSON 风格的轻量级的授权和身份认证规范,可实现无状态、分布式的 Web 应用授权

JWT 作为一种规范,并没有和某一种语言绑定在一起,常用的 Java 实现是 GitHub 上的开源项目 jjwt,地址如下

JWT 包含三部分数据

  • Header:头部,通常头部有两部分信息

    • 声明类型,这里是JWT
    • 加密算法,自定义

我们会对头部进行 base64Url 编码(可解码,得到第一部分数据。

  • Payload:载荷,就是有效数据,在官方文档中(RFC7519),这里给了7个示例信息

    • iss (issuer):表示签发人
    • exp (expiration time):表示token过期时间
    • sub (subject):主题
    • aud (audience):受众
    • nbf (Not Before):生效时间
    • iat (Issued At):签发时间
    • jti (JWT ID):编号

这部分也会采用 base64Url 编码,得到第二部分数据。

  • Signature:签名,是整个数据的认证信息。一般根据前两步的数据,再加上服务的的密钥secret(密钥保存在服务端,不能泄露给客户端,通过 Header 中配置的加密算法生成。用于验证整个数据完整和可靠性。

生成的数据格式如下图

注意,这里的数据通过 隔开成了三部分,分别对应前面提到的三部分,另外,这里数据是不换行的,图片换行只是为了展示方便而已。

流程图

步骤翻译

  1. 应用程序或客户端向授权服务器请求授权
  2. 获取到授权后,授权服务器会向应用程序返回访问令牌
  3. 应用程序使用访问令牌来访问受保护资源(如 API

因为 JWT 签发的 token 中已经包含了用户的身份信息,并且每次请求都会携带,这样服务的就无需保存用户信息,甚至无需去数据库查询,这样就完全符合了 RESTful 的无状态规范。

说了这么多,JWT 也不是天衣无缝,由客户端维护登录状态带来的一些问题在这里依然存在,举例如下

  1. 续签问题,这是被很多人诟病的问题之一,传统的 cookie+session 的方案天然的支持续签,但是 jwt 由于服务端不保存用户状态,因此很难完美解决续签问题,如果引入 redis,虽然可以解决问题,但是 jwt 也变得不伦不类了。
  2. 注销问题,由于服务端不再保存用户信息,所以一般可以通过修改 secret 来实现注销,服务端 secret 修改后,已经颁发的未过期的 token 就会认证失败,进而实现注销,不过毕竟没有传统的注销方便。
  3. 密码重置,密码重置后,原本的 token 依然可以访问系统,这时候也需要强制修改 secret。
  4. 基于第 2 点和第 3 点,一般建议不同用户取不同 secret。

对于上面提到的这些问题,在目前具体的项目实践中,更多的是通过引入 Redis 来解决这些问题。

说了这么久,接下来我们就来看看这个东西到底要怎么用

首先我们来创建一个 Spring Boot 项目,创建时需要添加 Spring Security 依赖,创建完成后,添加 依赖,完整的 pom.xml 文件如下

 

然后在项目中创建一个简单的 User 对象实现 UserDetails 接口,如下

 

这个就是我们的用户对象,先放着备用,再创建一个 HelloController,内容如下

 

HelloController 很简单,这里有两个接口,设计是 接口可以被具有 user 角色的用户访问,而 接口则可以被具有 admin 角色的用户访问。

先准备一个 JWT 操作的工具类

 

接下来,在用户登录成功的时候,生成 JWT 字符串,并存入到 Redis 中,如下

 

最后再来一个校验的过滤器,在用法发送请求的时候,校验 JWT 字符串,如下

 

关于这个过滤器,我说如下几点

  1. 首先从请求头中提取出 Authorization 字段,这个字段对应的 value 就是用户的 token。
  2. 将提取出来的 token 字符串调用 JwtUtils.verifyToken 方法进行验证,将验证结果放到当前的 SecurityContext 中,然后执行过滤链使请求继续执行下去。

最后,在 Spring Security 中配置这个过滤器。

 

搞定

做完这些之后,我们的环境就算完全搭建起来了,接下来启动项目然后在 POSTMAN 中进行测试,如下

登录成功后返回的字符串就是经过 base64url 转码的 token,一共有三部分,通过一个 隔开,我们可以对第一个 之前的字符串进行解码,即 Header,如下

再对两个 之间的字符解码,即 payload

可以看到,我们设置信息,由于 base64 并不是加密方案,只是一种编码方案,因此,不建议将敏感的用户信息放到 token 中。

接下来再去访问 接口,注意认证方式选择 Bearer Token,Token 值为刚刚获取到的值,如下

可以看到,访问成功。

本文地址:http://ww.kub2b.com/news/20985.html     企库往 http://ww.kub2b.com/ ,  查看更多

特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。

 
 
更多>同类最新文章
0相关评论

文章列表
相关文章
最新动态
推荐图文
最新文章
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号