构建现代微服务安全体系:Spring Security、JWT 与 Spring Cloud Gateway 实践
构建现代微服务安全体系:Spring Security、JWT 与 Spring Cloud Gateway 实践
本文将基于提供的代码示例,详细介绍如何在一个Java微服务项目中使用Spring Security、JWT和Spring Cloud Gateway来构建一个高效且安全的微服务体系,并整合性能优化措施。
基础流程
- 登录认证:客户端通过用户名和密码获取JWT
流程描述:客户端发送包含用户名和密码的登录请求到身份验证端点。服务器验证这些凭据的有效性后,使用JwtTokenProvider生成一个JWT,并将其返回给客户端。
关键点:
客户端在成功登录后保存JWT,通常是在HTTP头中以Authorization: Bearer 的形式携带。
JWT包含了用户的身份信息(如用户ID、角色等)以及过期时间。 - 请求路由:Gateway验证JWT签名和基础有效性
流程描述:当客户端发起API请求时,Spring Cloud Gateway首先拦截请求,通过JwtAuthenticationWebFilter过滤器来验证JWT的签名是否正确及令牌的基础有效性(如是否过期)。
关键点:
使用JwtTokenProvider中的方法来解析和验证JWT。
如果验证失败,直接返回错误响应;如果成功,则继续处理请求。 - 上下文传递:微服务解析JWT生成SecurityContext
流程描述:一旦Gateway验证了JWT的有效性,请求被转发到相应的微服务。在微服务内部,JwtAuthenticationTokenFilter再次检查JWT,从中提取用户信息并创建UsernamePasswordAuthenticationToken对象,然后将这个对象设置到Spring Security上下文中。
关键点:
JwtTokenProvider用于从JWT中提取用户信息(如用户ID、角色等),并据此构建认证对象。
这个步骤确保了每个请求都能在微服务层面上识别出当前用户及其权限。 - 权限校验:方法级注解实现动态权限控制
流程描述:在微服务的方法上应用Spring Security提供的注解(如@PreAuthorize或@Secured),根据用户的角色或权限动态地控制对资源的访问。
关键点:
利用Spring Security的表达式语言支持,可以灵活地定义访问控制规则。
只有当用户的权限满足特定条件时,才能执行受保护的方法或访问特定的资源。 - 令牌刷新:通过Refresh Token无感续期Access Token
流程描述:为了延长用户的会话而不需重新登录,系统提供了一个刷新令牌(Refresh Token)。当Access Token即将过期时,客户端可以使用Refresh Token向服务器请求新的Access Token。
关键点:
Refresh Token的安全存储非常重要,应确保其不能轻易被第三方获取。
实现逻辑需要确保旧的Access Token失效,并生成一个新的有效期内的Access Token返回给客户端。
具体实现
1. Spring Security 配置
首先,我们从Spring Security配置开始。你已经提供了一个基本的SecurityConfig
类,它负责配置认证和授权管理。以下是基于你的代码示例进行的一些优化和扩展:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsServiceImpl userDetailsService;@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;@Autowiredprivate AuthenticationEntryPoint authenticationEntryPoint;@Autowiredprivate AccessDeniedHandler accessDeniedHandler;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class).authorizeRequests().antMatchers("/auth/register", "/auth/login").permitAll().anyRequest().authenticated().and().exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler).and().cors();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}
}
性能优化点:
- 禁用不必要的过滤器链: 如
WebAsyncManagerIntegrationFilter
等,以减少过滤器链长度,提高性能。 - 启用预授权功能: 使用
@EnableGlobalMethodSecurity(prePostEnabled = true)
注解启用方法级别的权限控制,减少不必要的安全性检查。
2. JWT Filter 实现
接下来是JWT过滤器的实现,用于在请求到达服务之前验证JWT的有效性。这里我们还将集成缓存策略以提高性能。
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate JwtTokenProvider jwtTokenProvider; // 使用JwtTokenProvider@Autowiredprivate StringRedisTemplate redisTemplate;// Caffeine Cache for token parsing results cachingprivate final Cache<String, Claims> tokenCache = Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(10, TimeUnit.MINUTES).build();@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String token = request.getHeader("token");if (token == null) {filterChain.doFilter(request, response);return;}Claims claims = getCachedClaims(token);if (claims == null) {// 使用JwtTokenProvider的validateToken方法验证token,并获取Claimsif(jwtTokenProvider.validateToken(token)) {// 假设JwtTokenProvider有一个getClaimsFromToken方法用于获取Claimsclaims = jwtTokenProvider.getClaimsFromToken(token);setCachedClaims(token, claims);} else {throw new RuntimeException("无效的JWT令牌");}}String userId = (String) claims.get("userId");String redisKey = "login:" + userId;String userStr = redisTemplate.opsForValue().get(redisKey);LoginUser loginUser = JSONUtil.toBean(userStr, LoginUser.class);if (loginUser == null) {throw new RuntimeException("用户未登录");}UsernamePasswordAuthenticationToken authenticationToken =new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authenticationToken);filterChain.doFilter(request, response);}private Claims getCachedClaims(String token) {return tokenCache.getIfPresent(token);}private void setCachedClaims(String token, Claims claims) {tokenCache.put(token, claims);}
}
性能优化点:
- Caffeine Cache: 在解析JWT时先检查缓存,避免重复解析带来的性能损耗。
3. Spring Cloud Gateway 中集成 JWT 验证
为了让Gateway能够提前验证JWT,我们需要在Gateway层添加相应的过滤器。
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/**
* 一个使用Spring Cloud Gateway的路由定位器(RouteLocator),它配置了一个路由规则,
* 用于将匹配特定路径模式的请求转发到指定的服务,并在转发前通过一个过滤器(JwtAuthenticationWebFilter)进行处理。
*/
@Configuration
public class GatewayConfig {@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder builder) {return builder.routes().route("service_route", r -> r.path("/service/**").filters(f -> f.filter(new JwtAuthenticationWebFilter())).uri("lb://service")).build();}
}
public class JwtAuthenticationWebFilter implements GatewayFilter, Ordered {private final JwtTokenProvider jwtTokenProvider;public JwtAuthenticationWebFilter(JwtTokenProvider jwtTokenProvider) {this.jwtTokenProvider = jwtTokenProvider;}/*** filter方法是过滤器的核心逻辑,每当有请求经过时都会调用此方法。* 首先从请求中提取JWT令牌(resolveToken)。* 如果令牌存在且有效,则使用jwtTokenProvider获取对应的认证信息(Authentication)。* 将认证信息设置到SecurityContext中,以便后续处理可以访问到当前用户的身份信息。* 最后,继续处理请求链(chain.filter(exchange)),即将请求传递给下一个过滤器或目标服务*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();String token = resolveToken(request);if (token != null && jwtTokenProvider.validateToken(token)) {Authentication auth = jwtTokenProvider.getAuthentication(token);SecurityContext securityContext = SecurityContextHolder.createEmptyContext();securityContext.setAuthentication(auth);SecurityContextHolder.setContext(securityContext);}return chain.filter(exchange);}private String resolveToken(ServerHttpRequest request) {String bearerToken = request.getHeaders().getFirst("Authorization");if (bearerToken != null && bearerToken.startsWith("Bearer ")) {return bearerToken.substring(7);}return null;}@Overridepublic int getOrder() {return -200; // 设置优先级}
}
4. JWT Token 的生成与刷新机制
为了提高用户体验,可以实现refresh token机制,允许用户通过refresh token获取新的access token。
@PostMapping("/token/refresh")
public ResponseEntity<?> refreshToken(@RequestBody TokenRefreshRequest request) {String refreshToken = request.getRefreshToken();if (jwtTokenProvider.validateToken(refreshToken)) {String accessToken = jwtTokenProvider.generateAccessTokenFromUsername(jwtTokenProvider.getUsernameFromToken(refreshToken));return ResponseEntity.ok(new TokenRefreshResponse(accessToken, refreshToken));} else {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid refresh token");}
}
5. 监控关键指标
为了及时发现潜在的安全威胁,加入监听并记录Spring Security的安全事件。
@EventListener
public void monitorAuthEvents(AbstractAuthenticationEvent event) {if(event instanceof AuthenticationSuccessEvent){log.info("认证成功: {}", event.getAuthentication().getName());} else if(event instanceof AuthenticationFailureBadCredentialsEvent){metrics.increment("auth.failure.bad_credentials");}
}
这些措施包括了禁用不必要的过滤器链、使用Caffeine Cache缓存JWT解析结果等,确保系统既安全又高效。
相关文章:
构建现代微服务安全体系:Spring Security、JWT 与 Spring Cloud Gateway 实践
构建现代微服务安全体系:Spring Security、JWT 与 Spring Cloud Gateway 实践 本文将基于提供的代码示例,详细介绍如何在一个Java微服务项目中使用Spring Security、JWT和Spring Cloud Gateway来构建一个高效且安全的微服务体系,并整合性能优…...
Spring Boot 动态数据源实操指南
在实际开发中,我们经常会遇到需要动态切换数据源的场景,比如多租户系统、读写分离、分库分表等。Spring Boot 提供了灵活的配置方式,结合 AbstractRoutingDataSource 可以轻松实现动态数据源切换。本文将带你一步步实现 Spring Boot 动态数据…...
HBase高级技巧:解锁更强大的数据处理能力
HBase高级技巧:解锁更强大的数据处理能力 嘿,小伙伴们!在掌握了HBase的基本操作之后,今天我们将深入探讨一些HBase的高级技巧。这些技巧将帮助你在面对复杂的数据处理需求时更加得心应手,进一步提升系统的性能和可靠性…...

【进阶】JVM篇
为什么学习jvm 1、面试的需要 学过java的程序员对jvm应该不陌生,程序员为什么要学习jvm呢?其实不懂jvm也可以照样写出优质的代码,但是不懂jvm会被大厂的面试官虐的体无完肤。 2、高级程序员需要了解 jvm作用 jvm负责把编译后的字节码转换…...

DeepSeek官方推荐的AI集成系统
DeepSeek模型虽然强大先进,但是模型相当于大脑,再聪明的大脑如果没有输入输出以及执行工具也白搭,所以需要有配套工具才能让模型发挥最大的作用。下面是一个典型AI Agent架构图,包含核心组件与数据流转关系: #mermaid-…...

【动态规划篇】:当回文串遇上动态规划--如何用二维DP“折叠”字符串?
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨ 文章所属专栏:动态规划篇–CSDN博客 文章目录 一.回文串类DP核心思想(判断所有子串是否是回文…...

JENKINS(全面)
一.linux系统中JENKINS的安装 注意:安装jenkins需要安装jdk,而且具体版本的jenkins有相对应的jdk版本。可参考以下链接。 Redhat Jenkins 软件包https://pkg.jenkins.io/redhat-stable/https://pkg.jenkins.io/redhat-stable/https://pkg.jenkins.io/r…...
Promise详解大全:介绍、九个方法使用和区别、返回值详解
Promise的介绍 Promise是异步编程的一种解决方案,它的构造函数是同步执行的,then 方法是异步执行的,所以Promise创建后里面的函数会立即执行,构造函数中的resolve和reject只有第一次执行有效,,也就是说Pro…...

尚硅谷爬虫note004
一、urllib库 1. python自带,无需安装 # _*_ coding : utf-8 _*_ # Time : 2025/2/11 09:39 # Author : 20250206-里奥 # File : demo14_urllib # Project : PythonProject10-14#导入urllib.request import urllib.request#使用urllib获取百度首页源码 #1.定义一…...
Debezium系列之:时区转换器,时间戳字段转换到指定时区
Debezium系列之:时区转换器,时间戳字段转换到指定时区 示例:基本配置应用TimezoneConverter SMT的效果示例:高级配置配置选项当Debezium发出事件记录时,记录中的时间戳字段的时区值可能会有所不同,这取决于数据源的类型和配置。为了在数据处理管道和应用程序中保持数据一…...

ubuntu20.04声音设置
step1:打开pavucontrol,设置Configuration和Output Devices, 注意需要有HDMI / DisplayPort (plugged in)这个图标。如果没有,就先选择Configuration -> Digital Stereo (HDMI 7) Output (unplugged) (unvailable),…...
如何设置Python爬虫的User-Agent?
在Python爬虫中设置User-Agent是模拟浏览器行为、避免被目标网站识别为爬虫的重要手段。User-Agent是一个HTTP请求头,用于标识客户端软件(通常是浏览器)的类型和版本信息。通过设置合适的User-Agent,可以提高爬虫的稳定性和成功率…...

深度学习框架探秘|TensorFlow:AI 世界的万能钥匙
在人工智能(AI)蓬勃发展的时代,各种强大的工具和框架如雨后春笋般涌现,而 TensorFlow 无疑是其中最耀眼的明星之一。它不仅被广泛应用于学术界的前沿研究,更是工业界实现 AI 落地的关键技术。今天,就让我们…...

C++:高度平衡二叉搜索树(AVLTree) [数据结构]
目录 一、AVL树 二、AVL树的理解 1.AVL树节点的定义 2.AVL树的插入 2.1更新平衡因子 3.AVL树的旋转 三、AVL的检查 四、完整代码实现 一、AVL树 AVL树是什么?我们对 map / multimap / set / multiset 进行了简单的介绍,可以发现,这几…...

建筑兔零基础自学python记录18|实战人脸识别项目——视频检测07
本次要学视频检测,我们先回顾一下图片的人脸检测建筑兔零基础自学python记录16|实战人脸识别项目——人脸检测05-CSDN博客 我们先把上文中代码复制出来,保留红框的部分。 然后我们来看一下源代码: import cv2 as cvdef face_detect_demo(…...

【MySQL数据库】Ubuntu下的mysql
目录 1,安装mysql数据库 2,mysql默认安装路径 3,my.cnf配置文件? 4,mysql运用的相关指令及说明 5,数据库、表的备份和恢复 mysql是一套给我们提供数据存取的,更加有利于管理数据的服务的网络程序。下…...

[MySQL#1] database概述 常见的操作指令 MySQL架构 存储引擎
#1024程序员节|征文# 目录 一. 数据库概念 0.连接服务器 1. 什么是数据库 口语中的数据库 为什么数据不直接以文件形式存储,而需要使用数据库呢? 总结 二. ??基础操作 三. 主流数据库 四. 基础知识 服务器,数据库&…...

1.从零开始学会Vue--{{基础指令}}
全新专栏带你快速掌握Vue2Vue3 1.插值表达式{{}} 插值表达式是一种Vue的模板语法 我们可以用插值表达式渲染出Vue提供的数据 1.作用:利用表达式进行插值,渲染到页面中 表达式:是可以被求值的代码,JS引擎会将其计算出一个结果 …...

VS2022中.Net Api + Vue 从创建到发布到IIS
VS2022中.Net Api Vue 从创建到发布到IIS 前言一、先决条件二、创建项目三、运行项目四、增加API五、发布到IIS六、设置Vue的发布 前言 最近从VS2019 升级到了VS2022,终于可以使用官方的.Net Vue 组合了,但是使用过程中还是有很多问题,这里记录一下. 一、先决条件 Visual …...

RFID技术在制造环节的应用与价值
在现代制造业中,信息化和智能化已经成为企业提升竞争力的重要手段。RFID技术因其非接触式、远距离和高效识别的特点,广泛应用于生产的多个环节。本文将详细解读生产过程中RFID的关键应用场景,并结合实际案例,展示其为制造业带来的…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...

[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...
算法250609 高精度
加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...
比特币:固若金汤的数字堡垒与它的四道防线
第一道防线:机密信函——无法破解的哈希加密 将每一笔比特币交易比作一封在堡垒内部传递的机密信函。 解释“哈希”(Hashing)就是一种军事级的加密术(SHA-256),能将信函内容(交易细节…...