SpringCloud实现权限管理(网关+jwt版)

 更新时间:2025年10月31日 09:37:04   作者:一介输生  
本文主要介绍了SpringCloud实现权限管理(网关+jwt版),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

首先要想一个问题:为什么微服务不能像普通的Spring Boot项目一样鉴权?其实并不是不能,而是不适合。 在微服务架构中使用 Spring Security + RBAC/JET 时,会面临 "重复鉴权" 的核心痛点。下面从技术原理到解决方案完整解析这个问题。

问题本质:为什么会有重复鉴权?

传统单体架构流程

所有权限校验集中在一个应用内完成 • 用户登录后,Session或Token在单应用中全局有效

微服务架构下的流程

每个微服务都需要独立完成:

  1. 解析Token
  2. 查询数据库验证权限
  3. 构建SecurityContext

假设有3个服务链式调用:

客户端 → 网关 → 服务A → 服务B → 服务C 每个服务都重复: 查询用户数据(1次DB查询) 查询权限数据(1次DB查询) ​​总查询次数 = 3服务 × 2查询 = 6次​ • 在服务交叉的时候,导致 多次数据库查询重复计算,使数据库压力倍增和网络开销叠加。

(1)创建 JWT 工具类

在util模块下创建JWT 工具类

@Component
public class JwtTokenUtil {
    // 密钥,用于签名和验证 JWT,应妥善保管
    @Value("${jwt.secret}")
    private String secret;
    // JWT 的过期时间,这里设置为 10 小时
    @Value("${jwt.expiration}")
    private Long expiration;

    // 根据用户详细信息生成 JWT
    public String generateToken(SysRoleNameUserId sysRoleNameUserId) {
        //自定义的声明
        Map<String, Object> claims = new HashMap<>();
        //鉴权所需的权限角色
        claims.put("identities",sysRoleNameUserId.getRoleNames());
        return createToken(claims, String.valueOf(sysRoleNameUserId.getUserId()));
    }

    // 创建 JWT 的具体方法
    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
                .setClaims(claims)//自定义的声明
                .setSubject(subject)//存的用户id
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(SignatureAlgorithm.HS256, secret)
                .compact();
    }

    //解析jwt
    public Claims extractAllClaims(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(secret)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }
}

JWT 的密钥(jwt.secret)应通过配置中心(如 Nacos)或环境变量注入,避免硬编码。这里选择环境变量注入: 在util模块下的application.yml配置文件里面指定

jwt:
  secret: your-secret-key-here-must-be-at-least-256-bits-long
  expiration: 1000 * 60 * 60 * 10 # 10 hour

(2)创建JwtFilter

在gateway网关模块创建JwtFilter过滤器来验证并解析jwt,从而获取权限信息

@Component
public class JwtFilter implements GlobalFilter, Ordered {

    @Resource
    private JwtTokenUtil jwtTokenUtil;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders headers = request.getHeaders();
        List<String> authHeader = headers.get("Authorization");
        if (authHeader != null && authHeader.get(0).startsWith("Bearer ")) {
            String token = authHeader.get(0).substring(7);
            // 验证 JWT 并提取角色信息
            Claims claims = null;
            try{
                claims = jwtTokenUtil.extractAllClaims(token);
            }catch (IllegalArgumentException e) {
                //解析 JWT 时发生其他错误
                System.out.println("解析 token 时发生其他错误");
            } catch (ExpiredJwtException e) {
                //JWT 已过期
                System.out.println("token 已过期");
            }
            //取出权限角色列表
            Object identitiesObj = claims.get("identities");
            List<GrantedAuthority> authorities = new ArrayList<>();
            if (identitiesObj instanceof List<?>) {
                for (Object role : (List<?>) identitiesObj) {
                    if (role instanceof String) {
                        // 将字符串转换为 SimpleGrantedAuthority
                        authorities.add(new SimpleGrantedAuthority((String) role));
                    }
                }
            }
            String userId = claims.getSubject();
            //将 Authentication 对象设置到 SecurityContextHolder 中后,Spring Security 就能在后续的授权过程中使用这些权限信息了。
            Authentication authentication = new UsernamePasswordAuthenticationToken(userId, null, authorities);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

(3)配置 Spring Security

在网关gateway模块配置所有微服务整体的权限管理规则:

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        http.csrf().disable()// 关闭 CSRF(跨站请求伪造)防护。在无状态 API(如 JWT 场景)中,CSRF 防护不必要(通常依赖 Authorization 头而非 Cookie)。 避免对 POST、PUT 等请求要求携带 CSRF Token。
                .authorizeExchange()
                .pathMatchers("/api/product/**").permitAll()
                .pathMatchers("/admin/**").permitAll()
                .anyExchange().authenticated();
        return http.build();
    }
}

如果各个微服务还需要独自的更细粒度的权限控制,只需要在单个微服务模块中单独配置一个Spring Security就行了。

到此这篇关于SpringCloud实现权限管理(网关+jwt版)的文章就介绍到这了,更多相关SpringCloud 权限管理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • idea撤销git commit操作详解

    idea撤销git commit操作详解

    这篇文章主要为大家介绍了idea撤销git commit操作详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • java开发中为什么双重效验锁要加volatile

    java开发中为什么双重效验锁要加volatile

    这篇文章主要为大家介绍了java开发中为什么双重效验锁要加volatile原理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • Java使用JCommander实现解析命令行参数

    Java使用JCommander实现解析命令行参数

    jcommander 是一个只有几十 kb 的 Java 命令行参数解析工具,可以通过注解的方式快速实现命令行参数解析,本文就来和大家介绍一下JCommander是如何解析命令行参数吧
    2023-06-06
  • Java获得元素属性的注解信息的步骤

    Java获得元素属性的注解信息的步骤

    在Java编程中,注解是一种为代码添加元数据的方式,通过反射机制,我们可以获取元素属性上的注解信息,这个过程对于框架开发和元数据处理非常有用,能够实现更灵活的功能,对java获得元素属性的注解信息相关知识感兴趣的朋友一起看看吧
    2024-09-09
  • java使用Runtime执行系统命令遇到的问题

    java使用Runtime执行系统命令遇到的问题

    这篇文章主要介绍了java使用Runtime执行系统命令遇到的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • java匿名内部类实例代码详解

    java匿名内部类实例代码详解

    这篇文章主要介绍了java匿名内部类实例代码详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • 排序算法图解之Java归并排序的实现

    排序算法图解之Java归并排序的实现

    归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。本文主要介绍了归并排序的实现,需要的可以参考一下
    2022-11-11
  • Java如何通过反射取实体类字段取值

    Java如何通过反射取实体类字段取值

    这篇文章主要介绍了Java如何通过反射取实体类字段取值问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • 掌握SpringMVC中@InitBinder的实际应用

    掌握SpringMVC中@InitBinder的实际应用

    这篇文章主要介绍了掌握SpringMVC中@InitBinder的实际应用,@InitBinder是Spring MVC框架中的一个注解,用于自定义数据绑定的方法,通过在控制器中使用@InitBinder注解,可以将特定的数据绑定逻辑应用于请求参数的处理过程中,需要的朋友可以参考下
    2023-10-10
  • SpringMVC如何获取多种类型数据响应

    SpringMVC如何获取多种类型数据响应

    这篇文章主要介绍了SpringMVC如何获取多种类型数据响应,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-11-11

最新评论