JWT技术

article/2025/11/9 15:50:39

JWT

一、 JWT 实现无状态 Web 服务

1、什么是有状态

有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。

例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。

缺点是什么?

  • 服务端保存大量数据,增加服务端压力
  • 服务端保存用户状态,无法进行水平扩展
  • 客户端请求依赖服务端,多次请求必须访问同一台服务器

2、什么是无状态

服务器不需要记录客户端的状态信息,即:

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

带来的好处是什么呢?

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

3、如何实现无状态

无状态登录的流程:

  • 当客户端第一次请求服务时,服务端对用户进行信息认证(登录)
  • 认证通过,将用户信息进行加密形成token,返回给客户端,作为登录凭证
  • 以后每次请求,客户端都携带认证的token
  • 服务的对token进行解密,判断是否有效。

流程图:

​ 客户端请求登录,登录之后颁发凭证

整个登录过程中,最关键的点是什么?

token的安全性

token是识别客户端身份的唯一标示,如果加密不够严密,被人伪造那就完蛋了。

采用何种方式加密才是安全可靠的呢?

我们将采用:JWT + RSA非对称加密

4、JWT简介

JWT全称是Json Web Token, 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;官网:https://jwt.io

JWT包含三部分数据:

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

    • 声明类型,这里是JWT 自描述信息

    我们会对头部进行base64编码,得到第一部分数据 base64编码和解码的

  • Payload:载荷,就是有效数据,一般包含下面信息:

    • 用户身份信息(注意,这里因为采用base64编码,可解码是可逆的,因此不要存放敏感信息)
    • 注册声明:如token的签发时间,过期时间,签发人等 这部分内容 好比身份证的信息

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

  • Signature:签名,是整个数据的认证信息。一般根据前两步的数据,再加上密钥(secret)(不要泄漏,最好周期性更换),通过加密算法(不可逆的)生成一个签名。用于验证整个数据完整和可靠性。

生成的数据格式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lLsk4cfM-1679728889833)(assets\image-20210824192550245.png)]

可以看到分为3段,每段就是上面的一部分数据

5、JWT交互流程

步骤翻译:

  • 1、用户登录
  • 2、服务的认证,通过后生成jwt
  • 3、将生成的jwt返回给浏览器
  • 4、用户每次请求携带jwt
  • 5、服务端利用公钥解读jwt签名,判断签名有效后,从Payload中获取用户信息
  • 6、处理请求,返回响应结果

二、nimbus-jose-jwt 库

1、进入依赖

nimbus-jose-jwt、jose4j、java-jwt 是几个 Java 中常见的操作 JWT 的库

nimbus-jose-jwt 官网:https://connect2id.com/products/nimbus-jose-jwt

所需坐标

    <dependency><groupId>com.nimbusds</groupId><artifactId>nimbus-jose-jwt</artifactId><version>9.11.1</version></dependency>

2、核心 API

2.1、加密过程

  • 在 nimbus-jose-jwt 中,使用 Header 类代表 JWT 的头部,不过,Header 类是一个抽象类,我们使用的是它的子类 JWSHeader

    创建头部对象:

     @Testpublic void createToken(){//创建头部对象JWSHeader jwsHeader =new JWSHeader.Builder(JWSAlgorithm.HS256) // 加密算法.type(JOSEObjectType.JWT) // 静态常量.build();System.out.println(jwsHeader);}
    

    你可以通过 .toBase64URL() 方法求得头部信息的 Base64 形式(这也是 JWT 中的实际头部信息):

  • 使用 Payload 类的代表 JWT 的荷载部分

    创建荷载部对象:

        @Testpublic void createToken(){//创建头部对象JWSHeader jwsHeader =new JWSHeader.Builder(JWSAlgorithm.HS256)       // 加密算法.type(JOSEObjectType.JWT) // 静态常量.build();System.out.println(jwsHeader);//创建载荷Payload payload = new Payload("hello world");System.out.println(payload);}
    

    你可以通过 .toBase64URL() 方法求得荷载部信息的 Base64 形式(这也是 JWT 中的实际荷载部信息):

  • 签名部分

    ​ 签名部分没有专门的类表示,签名部分并非你自己创建出来的,而是靠 头部 + 荷载部 + 加密算法 算出来的

    ​ nimbus-jose-jwt 专门提供了一个签名器 JWSSigner ,用来参与到签名过程中。密钥就是在创建签名器的时候指定的:

    JWSSigner jwsSigner = new MACSigner("密钥");  //MACSigner()中要指定一个密钥
    

    最终,整个 JWT 由一个 JWSObject 对象表示:

    JWSObject jwsObject = new JWSObject(jwsHeader, payload);
    // 进行签名(根据前两部分生成第三部分)
    jwsObject.sign(jwsSigner);
    

    我们最终要的是 JWT 字符串,而不是对象,这里接着对代表 JWT 的 JWSObject 对象调用 .serialize() 方法即可:

    String token = jwsObject.serialize();
    

    完整示例:

      @Testpublic void createToken() throws JOSEException {//创建头部对象JWSHeader jwsHeader =new JWSHeader.Builder(JWSAlgorithm.HS256)       // 加密算法.type(JOSEObjectType.JWT) // 静态常量.build();//创建载荷Payload payload = new Payload("hello world");//创建签名器JWSSigner jwsSigner = new MACSigner("woniu");//woniu为密钥//创建签名JWSObject jwsObject = new JWSObject(jwsHeader, payload);// 头部+载荷jwsObject.sign(jwsSigner);//再+签名部分//生成token字符串String token = jwsObject.serialize();System.out.println(token);}
    

如果出现:com.nimbusds.jose.KeyLengthException: The secret length must be at least 256 bits异常,是因为密钥的长度不够增加密钥长度即可

2.2、 解密

反向的解密和验证过程核心 API 就 2 个:JWSObject 的静态方法 parse 方法和验证其 JWSVerifier 对象。

如果你想直接验证 JWSObject 对象的合法性,你需要创建一个 JWSVerifier 对象。

//创建验证器
JWSVerifier jwsVerifier = new MACVerifier("密钥");//密钥要和加密时的相同

然后直接调用 jwsObject 对象的 verify 方法:

if (!jwsObject.verify(jwsVerifier)) {throw new RuntimeException("token 签名不合法!");
}

三、token续期

在实际的开发中,token不可能一直有效,比如30分钟内一次都没有进行操作,则认证过期,需要重新登录,如果一直在进行请求访问则token一直有效,直到上一次访问距离下一次访问的时间超过了30分钟,则认证过期。

springsecurity整合JWT:

@Component
public class JWTfilter extends OncePerRequestFilter {@Autowiredprivate RedisTemplate<String, String> redisTemplate;@Autowired(required = false)private SecurityLoginService securityLoginService;@SneakyThrows@Overrideprotected void doFilterInternal(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,FilterChain filterChain)throws ServletException, IOException {//功能点1:在请求头拿到jwtString jwt = httpServletRequest.getHeader("jwt");if (jwt == null) {//放给security 其他过滤器,该方法不做处理filterChain.doFilter(httpServletRequest, httpServletResponse);return;}// 功能点2:jwt不合法if (!JWTUtil.decode(jwt)) {filterChain.doFilter(httpServletRequest, httpServletResponse);return;}//功能点3 获取jwt的用户信息Map payLoad = JWTUtil.getPayload(jwt);String username = (String) payLoad.get("username");//拿到redis的jwtString redisJWT = redisTemplate.opsForValue().get("jwt:" + username);//判断redis是否有该jwtif (redisJWT == null) {filterChain.doFilter(httpServletRequest, httpServletResponse);return;}if (!jwt.equals(redisJWT)) {filterChain.doFilter(httpServletRequest, httpServletResponse);return;}//给redis 的jwt续期redisTemplate.opsForValue().set("jwt:" + username, jwt, 30,TimeUnit.MINUTES);//获取用户名,密码,权限UserDetails userDetails = securityLoginService.loadUserByUsername(username);// 获取用户信息 生成security容器凭证UsernamePasswordAuthenticationToken upa =new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());//放入凭证SecurityContextHolder.getContext().setAuthentication(upa);// 本方法共功能执行完了,交给下一个过滤器filterChain.doFilter(httpServletRequest, httpServletResponse);}
}//前后端项目中要禁用掉session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
在securityConfig 类注入
http.addFilterAfter(jwtFilter, UsernamePasswordAuthenticationFilter.class);

http://chatgpt.dhexx.cn/article/uMJLdv6w.shtml

相关文章

token学习笔记(JWT、jjwt的使用及案例实现)

文章目录 1. 首先、了解什么是会话2. 会话跟踪的主要技术3. Token 令牌学习3.1 流程图3.2 token3.3 JWT(JSON web Tokens)Json web 令牌(规范)3.4 JWT结构3.5 JWT需要的依赖3.6 JWT的获取与验证流程3.7JWT的使用方式3.8 jjwt的使用&#xff08;创建JWT方式&#xff09;1. jjwt需…

JWT 进阶 -- JJWT

###jwt是什么? JWTs是JSON对象的编码表示。JSON对象由零或多个名称/值对组成&#xff0c;其中名称为字符串&#xff0c;值为任意JSON值。JWT有助于在clear(例如在URL中)发送这样的信息&#xff0c;可以被信任为不可读(即加密的)、不可修改的(即签名)和URL - safe(即Base64编码…

JWT详解和使用(jjwt)

JWT详解和使用 JWT是啥 JWT&#xff08;JSON Web Token&#xff09;是一个开放标准(RFC 7519)&#xff0c;它定义了一种紧凑的、自包含的方式&#xff0c;用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任&#xff0c;因为它是数字签名的。 下列场景中使用…

JJWT 实现JWT

1什么是JJWT JJWT 是一个提供端到端的 JWT 创建和验证的 Java 库。永远免费和开源 (Apache License&#xff0c;版本2.0)&#xff0c;JJWT 很容易使用和理解。它被设计成一个以建筑为中心的流畅界面&#xff0c;隐藏了它的大部分复杂性。 2JJWT快速入门 2.1token的创建 2.1…

什么是JWT?

在HTTP接口调用的时候&#xff0c;服务端经常需要对调用方做认证&#xff0c;以保证安全性。一种常见的认证方式是使用JWT(Json Web Token)&#xff0c;采用这种方式时&#xff0c;经常在header传入一个authorization字段&#xff0c;值为对应的jwt_token&#xff0c;或者也有图…

JWT的学习和JJWT的使用

1.什么是JWT JWT&#xff08;JSON Web Token&#xff09;是一个开放的行业标准&#xff0c;它定义了一种简介的&#xff0c;自包含的协议格式&#xff0c;用于在通信双方传递json对象&#xff0c;传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或者使用RSA的公…

JWT详解

本文从本人博客搬运&#xff0c;原文格式更加美观&#xff0c;可以移步原文阅读&#xff1a;JWT详解 JWT简介 1.什么是JWT 在介绍JWT之前&#xff0c;我们先来回顾一下利用token进行用户身份验证的流程&#xff1a; 客户端使用用户名和密码请求登录服务端收到请求&#xff…

JWT详解、JJWT使用、token 令牌

前言 在正式讲解JWT之前&#xff0c;我们先重温一下用户身份认证相关的一些概念&#xff1a; 有状态登录&#xff08;session认证&#xff09; 服务器当中记录每一次的登录信息&#xff0c;从而根据客户端发送的数据来判断登录过来的用户是否合法。 缺点&#xff1a; 每个用…

Java的JJWT实现JWT

1 什么是 JJWT JJWT 是一个提供端到端的 JWT 创建和验证的 Java 库。永远免费和开源 (Apache License&#xff0c;版本2.0)&#xff0c;JJWT 很容易使用和理解。它被设计成一个以建筑为中心的流畅界面&#xff0c;隐藏了它的大部分复杂性。 2 token 的创建 2.1 引入依赖 &l…

解决Red Hat虚拟机与主机网络不通

虚拟机版本&#xff1a;Red Hat Enterprise Linux 7 64 位 安装&#xff1a;自定义安装&#xff0c;带GUI的服务器&#xff0c;创建图形化界面 创建完毕后发现网络ping不通&#xff0c;经过查阅各种资料&#xff0c;在同事的帮助下终于解决。做一个记录。 1、VMware网络配置。…

虚拟机VMware和宿主机连接

文章目录 一、NAT连接1.查看宿主机IP地址2.设置VMnet8信息2.设置虚拟机模式3.设置虚拟网络4.设置虚拟机内系统IP&#xff08;Centos8.2为例&#xff09;4.1.图形化操作4.1.1DHCP4.1.2静态IP4.1.3 重启网卡&#xff08;修改网卡信息后&#xff09; 5.测试5.1.宿主机ping虚拟机5.…

VMware虚拟机三种网络连接模式详解

VMware虚拟机三种网络连接模式详解 Vmware提供了三种网络工作模式&#xff0c;分别是&#xff1a;&#xff08;1&#xff09;Bridged&#xff08;桥接模式&#xff09;&#xff1b;&#xff08;2&#xff09;NAT&#xff08;网络地址转换模式&#xff09;&#xff1b;&#xf…

虚拟机与主机之间通信

1.bridged(桥接方式&#xff0c;默认使用vmnet0虚拟网卡)&#xff1a; 选择这种模式&#xff0c;虚拟机等同于网络内的一台物理主机&#xff0c;可对手动设置IP&#xff0c;子网掩码。DNS&#xff0c;且IP地址要和主机的IP在同一网段内。这样。虚拟机就和主机如同连在一个HUB上…

虚拟机的几种网络连接方式

系列运维 文章目录 系列运维前言一、几种网络连接方式各是什么&#xff1f;二、网络连接的差异性总结 前言 VirtualBox中有4种网络连接方式&#xff1a; NAT Bridged Adapter Internal Host-only Adapter VMWare中有三种&#xff0c;VirtualBox只是比VMWare多了Internal方式。…

主机、虚拟机、开发板之间网络连接设置

最近在玩开发板&#xff0c;主机使用的无线网卡&#xff0c;开发板与主机网线直连&#xff0c;现在开发板想使用tftp直接从虚拟机下载镜像等文件&#xff0c;偶尔又需要虚拟机从主机下载文件&#xff0c;虚拟机有时候又需要网络&#xff0c;经过一番折腾算是调试成功。 1.主机…

vmware虚拟机与主机共享网络

我的虚拟机总是各种连不上网&#xff0c;每次都要折腾一番。现在我把虚拟机连不上网的原因总体排查一下&#xff0c;按照流程一步步来&#xff0c;基本上可以解决大部分人的问题。 首先&#xff0c;在VMware的编辑->虚拟网络编辑器重新建立&#xff2e;&#xff21;&#xf…

Virtualbox虚拟机与主机相互访问

刚从vmware切换到Virtualbox有些地方还是不太熟悉。网络连接这块就被卡了一下&#xff0c;后来发现其实很简单&#xff0c;是我想多了。 环境 主机&#xff1a; archlinux 虚拟机&#xff1a;windows 10 软件版本&#xff1a;VirtualBox 6.1 理论上这些环境不影响&#xff0…

虚拟机和主机无法连接

vm网络配置&#xff1a;https://www.cnblogs.com/aeolian/p/8882790.html 一、首先查看自己的虚拟机服务有没有开启&#xff0c;选择电脑里面的服务查看&#xff1b; 1.计算机点击右键选择管理 2.进入管理选择VM开头的服务如果没有开启的话就右键开启 二、虚拟机服务开启后就…

虚拟机和主机的网络访问

本人的问题是主机可以ping虚拟机&#xff0c;虚拟机可以正常访问端口&#xff0c;主机不能访问虚拟机端口&#xff0c;然后就进行各种问题的排查&#xff0c;一开始把所有的防火墙都关了还不行&#xff0c;所以来到了windows主机虚拟网卡这里设置&#xff0c;使用了手动设置虚拟…

VMwareWorkstationPro虚拟机与主机远程连接

目录 一 &#xff0c;虚拟机与主机远程连接环境设置 二 虚拟机与主机远程连接 一 &#xff0c;虚拟机与主机远程连接环境设置 1 点击设置打开系统选项 2 打开远程控制 3 点击设置打开更新和安全 4 关闭病毒防护和防火墙 &#xff08;注&#xff1a;主机与虚拟机都要执行…