最新Spring Security实战教程(十六)微服务间安全通信 - JWT令牌传递与校验机制

news2025/6/2 9:56:28

在这里插入图片描述

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页——Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用
✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧
💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整
🌞《Spring Security》专栏中我们将逐步深入Spring Security的各个技术细节,带你从入门到精通,全面掌握这一安全技术
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~

最新Spring Security实战教程(十六)微服务间安全通信 - JWT令牌传递与校验机制

  • 1. 前言
  • 2. 配置 Spring Security 6 与 Nimbus-JOSE-JWT
    • 2.1 引入依赖
    • 2.2 配置公钥和私钥
      • 2.2.1 生成公私钥对
      • 2.2.1 将密钥加载到 Spring Boot
  • 3. JWT 生成和验证
    • 3.1 生成 JWT 令牌
    • 3.2 验证 JWT 令牌
  • 4. 配置 Spring Security 资源服务器
  • 5. 服务间的 JWT 令牌传递与校验
    • 5.1 服务 A 生成 JWT
    • 5.2 客户端发送 JWT
    • 5.3 服务 B 校验 JWT
  • 6. 结语

回顾链接:
最新Spring Security实战教程(一)初识Spring Security安全框架
最新Spring Security实战教程(二)表单登录定制到处理逻辑的深度改造
最新Spring Security实战教程(三)Spring Security 的底层原理解析
最新Spring Security实战教程(四)基于内存的用户认证
最新Spring Security实战教程(五)基于数据库的动态用户认证传统RBAC角色模型实战开发
最新Spring Security实战教程(六)最新Spring Security实战教程(六)基于数据库的ABAC属性权限模型实战开发
最新Spring Security实战教程(七)方法级安全控制@PreAuthorize注解的灵活运用
最新Spring Security实战教程(八)Remember-Me实现原理 - 持久化令牌与安全存储方案
最新Spring Security实战教程(九)前后端分离认证实战 - JWT+SpringSecurity无缝整合
最新Spring Security实战教程(十)权限表达式进阶 - 在SpEL在安全控制中的高阶魔法
最新Spring Security实战教程(十一)CSRF攻防实战 - 从原理到防护的最佳实践
最新Spring Security实战教程(十二)CORS安全配置 - 跨域请求的安全边界设定
最新Spring Security实战教程(十三)会话管理机制 - 并发控制与会话固定攻击防护
最新Spring Security实战教程(十四)OAuth2.0精讲 - 四种授权模式与资源服务器搭建
最新Spring Security实战教程(十五)快速集成 GitHub 与 Gitee 的社交登录

1. 前言

在目前微服务架构中,服务间的安全通信至关重要。为了解决不同服务之间的认证与授权问题,常常使用 JSON Web Token (JWT) 作为令牌传递机制。JWT 是一种轻量级的令牌格式,包含了丰富的用户身份信息,并且可以被服务端验证。利用 Spring Security 6JWT,我们可以很容易地实现服务间的安全通信,确保服务间的请求只有经过授权的客户端才能发起。

在前面的第9个章节中,博主详细介绍了 JWT+SpringSecurity 的整合,这里将简单对JWT简单介绍带过,更多详细介绍感兴趣的小伙伴可以回顾 【最新Spring Security实战教程(九)前后端分离认证实战 - JWT+SpringSecurity无缝整合】

本文博主将带着小伙伴快速了解如何使用 Spring Security 6 配合 JWT 实现服务间的安全通信。

微服务间 JWT通信核心流程
在这里插入图片描述

2. 配置 Spring Security 6 与 Nimbus-JOSE-JWT

本章节博主使用的是 Nimbus-JOSE-JWT

2.1 引入依赖

<!-- OAuth2资源服务器支持 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<!-- JWT处理库(Nimbus实现) -->
<dependency>
    <groupId>com.nimbusds</groupId>
    <artifactId>nimbus-jose-jwt</artifactId>
    <version>9.37</version>
</dependency>

spring-boot-starter-oauth2-resource-server 提供了 Spring Security 中用于资源服务器的支持,nimbus-jose-jwt 则提供了生成和验证 JWT 的功能。

关键依赖说明:

依赖项作用必需场景
spring-boot-starter-security安全框架核心所有安全场景必须
spring-boot-starter-oauth2-resource-serverOAuth2资源服务器支持JWT验证必需
nimbus-jose-jwtJWT编码/解码实现JWT处理必需

2.2 配置公钥和私钥

为了使用 RSA 进行 JWT 签名和验证,我们需要配置私钥(用于签名)和公钥(用于验证)。可以将密钥存储为 PEM 格式的文件,并在 Spring Boot 配置中加载这些密钥。

2.2.1 生成公私钥对

首先,我们生成一个 RSA 公私钥对:

# 生成私钥(private.pem)
openssl genpkey -algorithm RSA -out private.pem -pkeyopt rsa_keygen_bits:2048

# 提取公钥(public.pem)
openssl rsa -pubout -in private.pem -out public.pem

2.2.1 将密钥加载到 Spring Boot

将私钥和公钥存储为文件,并在配置中加载它们:

# application.yml 配置公钥和私钥路径
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          public-key-location: classpath:public.pem
          private-key-location: classpath:private.pem

目前我们将密钥文件放在 resources 目录下,并通过配置 public-key-locationprivate-key-location 来加载它们。

也可以指定系统上其它目录

3. JWT 生成和验证

3.1 生成 JWT 令牌

我们需要创建一个方法,通过 RSA 私钥签名 JWT 令牌。使用 Nimbus-JOSE-JWT 来生成带有签名的 JWT

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;

import java.security.PrivateKey;
import java.util.Date;

public class JwtUtils {

    private final PrivateKey privateKey;

    public JwtUtils(PrivateKey privateKey) {
        this.privateKey = privateKey;
    }

    public String createJWT(String subject) throws Exception {
        JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                .subject(subject)
                .issueTime(new Date())
                .expirationTime(new Date(System.currentTimeMillis() + 3600000)) // 1 hour expiration
                .build();

        SignedJWT signedJWT = new SignedJWT(
                new JWSHeader(JWSAlgorithm.RS256),
                claimsSet
        );

        RSASSASigner signer = new RSASSASigner(privateKey);
        signedJWT.sign(signer);

        return signedJWT.serialize();
    }
}

此方法会根据传入的用户名(subject)生成一个 JWT 令牌,并使用 RSA 私钥进行签名。生成的 JWT 将包含基本的声明 (如 subject、issueTime 和 expirationTime)

3.2 验证 JWT 令牌

为了验证 JWT 令牌,我们需要使用 RSA 公钥来验证其签名。以下是使用 Nimbus-JOSE-JWT 库验证 JWT 的代码:

import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSASSAVerifier;
import com.nimbusds.jwt.SignedJWT;

import java.security.PublicKey;

public class JwtUtils {

    private final PublicKey publicKey;

    public JwtUtils(PublicKey publicKey) {
        this.publicKey = publicKey;
    }

    public boolean validateJWT(String token) throws Exception {
        SignedJWT signedJWT = SignedJWT.parse(token);

        RSASSAVerifier verifier = new RSASSAVerifier(publicKey);

        return signedJWT.verify(verifier);
    }
}

此方法会解析并验证传入的 JWT 令牌,使用 RSA 公钥验证签名的合法性。如果签名有效,它将返回 true,否则返回 false

4. 配置 Spring Security 资源服务器

这里我们将使用 Spring Security 配置资源服务器,确保每个请求都携带有效的 JWT 令牌,并使用 RSA 公钥验证令牌

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.decoder(jwtDecoder())));

        return http.build();
    }

    @Bean
    public JwtDecoder jwtDecoder() throws Exception {
        RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
                .generatePublic(new X509EncodedKeySpec(Files.readAllBytes(Paths.get("classpath:public.pem"))));
        return NimbusJwtDecoder.withPublicKey(publicKey).build();
    }
}

在上面的配置中,我们指定了 JwtDecoder,并且使用 NimbusJwtDecoder 来加载 RSA 公钥,并为每个请求验证 JWT 令牌。通过 oauth2ResourceServer(oauth2 -> oauth2.jwt()) 配置,Spring Security 会自动处理 JWT 校验

5. 服务间的 JWT 令牌传递与校验

5.1 服务 A 生成 JWT

服务 A 会在用户登录后生成 JWT,并将其返回给客户端:

@RestController
public class AuthController {

    private final JwtUtils jwtUtils;

    public AuthController(JwtUtils jwtUtils) {
        this.jwtUtils = jwtUtils;
    }

    @PostMapping("/login")
    public String login(@RequestBody LoginRequest loginRequest) throws Exception {
        if ("user".equals(loginRequest.getUsername()) && "password".equals(loginRequest.getPassword())) {
            return jwtUtils.createJWT(loginRequest.getUsername());
        }
        throw new UnauthorizedException("Invalid credentials");
    }
}

5.2 客户端发送 JWT

客户端将 JWT 令牌放入请求的 Authorization 头部:

public class RestClient {

    public static String getProtectedResource(String token) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + token);
        
        HttpEntity<String> entity = new HttpEntity<>(headers);
        
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.exchange(
            "http://localhost:8081/api/protected", 
            HttpMethod.GET, 
            entity, 
            String.class
        );
        return response.getBody();
    }
}

5.3 服务 B 校验 JWT

服务 B 会验证 JWT 令牌,确保请求是来自合法的客户端:

@RestController
@RequestMapping("/api")
public class ProtectedResourceController {

    @GetMapping("/protected")
    public ResponseEntity<String> getProtectedData() {
        return ResponseEntity.ok("This is a protected resource!");
    }
}

6. 结语

通过本章节的介绍,相信小伙伴们已经掌握了如何使用 JWTRSA 非对称加密在 Spring Security 6 中实现 JWT 令牌传递与校验机制。非对称加密的优势在于公钥可以公开分发,而私钥只由服务端持有,从而增加了系统的安全性。

当然本章节未引入 openfeign 作为服务间的调用,仅仅使用了最原始的 RestTemplate 进行其它服务的测试请求, 小伙伴们可以根据自己的需求调整并完善,进一步提升系统的安全性。

如果你在实践过程中有任何疑问或更好的扩展思路,欢迎在评论区留言,最后希望大家 一键三连 给博主一点点鼓励!


在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2386649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【五】Spring Cloud微服务开发:解决版本冲突全攻略

Spring Cloud微服务开发&#xff1a;解决版本冲突全攻略 目录 Spring Cloud微服务开发&#xff1a;解决版本冲突全攻略 概述 一、Spring Boot 二、Spring Cloud 三、Spring Cloud Alibaba 总结 概述 spring cloud微服务项目开发过程中经常遇到程序包版本冲突的问题&…

Spring Boot微服务架构(二):开发调试常见中文问题

Spring Boot开发调试常见中文问题及解决方案 一、环境配置类问题 端口冲突 表现&#xff1a;启动时报错"Address already in use"解决&#xff1a;修改application.properties中的server.port或终止占用端口的进程 数据库连接失败 表现&#xff1a;启动时报错"…

Linux基础IO----动态库与静态库

什么是库&#xff1f; 库是由一些.o文件打包在一起而形成的可执行程序的半成品。 如何理解这句话呢&#xff1f; 首先&#xff0c;一个程序在运行前需要进行预处理、编译、汇编、链接这几步。 预处理&#xff1a; 完成头文件展开、去注释、宏替换、条件编译等&#xff0c;最终…

LeetCode百题刷004(哈希表优化两数和问题)

遇到的问题都有解决的方案&#xff0c;希望我的博客可以为你提供一些帮助 一、哈希策略优化两数和问题 题目地址&#xff1a;1. 两数之和 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/two-sum/description/ 思路分析&#xff1a; 题目要求在一个整型…

FPGA通信之VGA与HDMI

文章目录 VGA基本概念&#xff1a;水平扫描&#xff1a;垂直扫描&#xff1a; 时序如下&#xff1a;端口设计疑问为什么需要输出那么多端口不输出时钟怎么保证电子枪移动速度符合时序VGA转HDMI 仿真电路图代码总结&#xff1a;VGA看野火电子教程 HDMITMDS传输原理为什么使用TMD…

Leetcode百题斩-二叉树

二叉树作为经典面试系列&#xff0c;那么当然要来看看。总计14道题&#xff0c;包含大量的简单题&#xff0c;说明这确实是个比较基础的专题。快速过快速过。 先构造一个二叉树数据结构。 public class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode…

ACM Latex模板:合并添加作者和单位

目录&#xff1a; 1.ACM会议论文Latex模板&#xff0c;逐个添加作者和单位&#xff1a; 1&#xff09;Latex&#xff1a; 2&#xff09;效果&#xff1a; 2. ACM会议论文Latex模板&#xff0c;合并添加作者和单位&#xff1a; 1&#xff09;Latex&#xff1a; 2&#x…

将MCP(ModelContextProtocol)与Semantic Kernel集成(调用github)

文章目录 将MCP&#xff08;ModelContextProtocol&#xff09;与Semantic Kernel集成&#xff08;调用github&#xff09;一、模型上下文协议&#xff08;MCP&#xff09;简介1.1 简介1.2 示例 二、集成步骤2.1 安装环境依赖2.2 构建语义内核&#xff08;Kernel&#xff09;2.3…

游戏引擎学习第311天:支持手动排序

仓库: https://gitee.com/mrxiao_com/2d_game_7(已满) 新仓库: https://gitee.com/mrxiao_com/2d_game_8 回顾并为今天的内容定下基调 我们接下来要继续完成之前开始的工作&#xff0c;上周五开始的部分内容&#xff0c;虽然当时对最终效果还不太确定&#xff0c;但现在主要任…

LambdaQueryWrapper、MybatisPlus提供的基本接口方法、增删改查常用的接口方法、自定义 SQL

DAY26.2 Java核心基础 MybatisPlus提供的基本接口方法 分页查询 导入依赖springboot整合Mybatis-plus <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version&g…

深度学习---可视化

模型可视化 深度学习模型可视化是理解、调试和优化模型的关键技术&#xff0c;涉及模型结构、参数、层输出、数据流动、训练过程等多维度分析。 一、可视化的核心作用 模型理解 解析复杂模型的网络架构&#xff08;如CNN的层级连接、Transformer的注意力机制&#xff09;。揭…

Windows系统如何查看ssh公钥

很多人只是一味的为拿到ssh公钥而努力&#xff0c;往往却会忽略了ssh公钥与私钥背后的作用。 咱们在这里会花两分钟。 一分钟速通概念&#xff0c;一分钟教会你如何获取。 一分钟速通概念&#xff1a; 如何生成&#xff1a; SHH 公钥 与 私钥 是基于非对称加密算法&#xff…

【2025】嵌入式软考中级部分试题

大题: 大模型 神经网络 机器学习 深度学习的包含关系 不一定对 订阅-发布者模型 发布/订阅模式特点: ①解耦:发布者和订阅者之间没有直接联系,它们通过中间的消息代理(如消息队列或事件总线)进行通信。这种解耦使得系统更加灵活,可以独立地添加或移除发布者和订阅者…

Antd中Upload组件封装及使用:

1.Upload上传组件功能: 文件校验 : 文件格式校验/文件大小校验/上传文件总个数校验 相关功能 : 拖拽功能/上传到远程(七牛)/文件删除及下载 2.组件效果展示: 3.疑难点及解决方案: Promise.all多文件并行上传到远程(七牛云): (1)在beforeUpload钩子函数中获取token (2)循环fi…

Linux环境基础开发工具->vim

引入&#xff1a;vim是什么&#xff1f; vs叫作继承开发环境&#xff0c;我们可以在里面编辑代码&#xff0c;调式代码&#xff0c;运行代码....这种叫集成开发环境&#xff1b;而vim只用来编辑代码&#xff0c;也就是类似于在windows上打开一个记事本来写代码的操作 集成开发…

跳板问题(贪心算法+细节思考)

首先直接看题&#xff1a; 这题直接贪心其实问题不大&#xff1a; 下面先展示我的一个错误代码&#xff1a; # include<iostream> # include<vector> # include<algorithm>using namespace std;int main() {int N,M;cin>>N>>M;vector<vecto…

RuoYi前后端分离框架集成UEditorPlus富文本编辑器

一、背景 采用若依框架搭建了一个小型的电子书项目,项目前端、后端、移动端就一人,电子书的章节内容是以富文本内容进行呈现的,产品设计人员直接给了一个第三方收费的富文本编辑器截图放到开发文档中,提了一沓需求点,概况下来就是要做成下图中的样子。作为一个后端开发人…

IPD流程落地:项目任务书Charter开发

目录 简介 第一个方面&#xff0c;回答的是Why的问题。 第二点&#xff0c;要回答做什么的问题&#xff0c;也就是产品定义What的问题。 第三点就是要回答执行策略与计划的问题&#xff0c;也就是How、When、Who的问题。 第四点是对上述这些分析的总结分析&#xff0c;要为…

Vue 2 混入 (Mixins) 的详细使用指南

1.基本概念 混入 (Mixins) 是 Vue 2 中用于组件代码复用的重要特性&#xff0c;它允许你将可复用的功能分发到多个组件中。 混入是一种灵活的代码复用方式&#xff0c;可以包含任意组件选项&#xff08;data、methods、生命周期钩子等&#xff09;。当组件使用混入时&#xff…

FreeRTOS 在物联网传感器节点的应用:低功耗实时数据采集与传输方案

FreeRTOS 在物联网传感器节点的应用&#xff1a;低功耗实时数据采集与传输方案 二、FreeRTOS 任务划分与优先级设计 任务名称优先级执行周期功能描述Sensor_Collect3100ms多传感器数据采集与预处理Data_Process2事件驱动数据滤波/压缩/异常检测LoRa_Transmit41s低功耗长距离数…