欢迎阅读我的文章!更多精彩内容,欢迎关注:
• B站主页
小枫Geek
• 微信公众号Procode  


在微服务架构中,安全问题往往比功能开发更棘手。 Spring Cloud Security 作为 Spring 体系下的安全解决方案,能帮助我们构建统一的认证和鉴权体系,但很多团队在接入过程中踩了不少坑。

这篇文章将从实战角度,带你逐步分析 Spring Cloud Security 中常见的 认证、鉴权、跨服务调用、安全配置 等问题,并给出解决思路。


1. 微服务安全的复杂性

在单体应用时代,安全防护主要集中在:

  • 用户认证(登录校验)

  • 权限控制(角色/资源绑定)

而微服务拆分之后,情况变得复杂:

  • 用户请求可能要经过 API Gateway → 多个业务服务 → 数据服务

  • 每个服务都要验证用户身份,否则链路中一旦有“短板”,就可能成为攻击入口;

  • 服务与服务之间的调用也要考虑 身份凭证传递,避免伪造请求。

Spring Cloud Security 就是为了解决这些问题,但在使用时也会暴露许多细节上的坑。

2. 踩坑一:OAuth2 认证服务配置混乱

很多团队在引入 Spring Cloud Security 时,第一步就是搭建 OAuth2 认证服务器。 常见的问题是:

  • 不同版本 Spring Cloud 的配置方式差异大 比如在 Spring Cloud Hoxton 之前,可以直接用 @EnableAuthorizationServer,而在 Spring Cloud 202x 之后,官方逐渐推荐使用 Spring Authorization Server,配置方式完全不同。

  • Token 解析失败 常见报错:

Invalid token
Cannot convert access token to JSON

根因往往是 JWT 公钥配置不一致资源服务没有正确配置解码器

解决方案

  • 新项目优先考虑 Spring Authorization Server,兼容性和维护性更强。

  • 在资源服务配置中明确指定解码器,例如:

@Bean
public JwtDecoder jwtDecoder() {
    return NimbusJwtDecoder.withPublicKey(rsaPublicKey).build();
}

3. 踩坑二:Feign 调用丢失 Token

在微服务间调用时,经常出现这样的问题:

  • 用户登录成功后请求 A 服务;

  • A 服务需要调用 B 服务;

  • 结果 B 服务报 401 Unauthorized。

根因:Feign 默认不会自动传递 Token。

解决方案: 通过 Feign RequestInterceptor 传递请求头:

@Bean
public RequestInterceptor requestInterceptor() {
    return requestTemplate -> {
        String token = SecurityContextHolder.getContext().getAuthentication().getCredentials().toString();
        requestTemplate.header(HttpHeaders.AUTHORIZATION, "Bearer " + token);
    };
}

这样就能保证下游服务也能识别到用户的身份。

4. 踩坑三:Gateway 跨域与安全过滤冲突

很多团队在 Spring Cloud Gateway 配置了 跨域(CORS),但结果认证请求始终报错。 常见场景:

  • 前端发送 OPTIONS 请求被拦截;

  • 登录接口直接 403 Forbidden。

解决方案: 在 Gateway 中要单独放行 OPTIONS 请求,并明确配置 CORS:

@Bean
public CorsWebFilter corsFilter() {
    CorsConfiguration config = new CorsConfiguration();
    config.addAllowedOrigin("*");
    config.addAllowedMethod("*");
    config.addAllowedHeader("*");
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return new CorsWebFilter(source);
}

同时,Spring Security 配置中要允许预检请求:

http.cors().and().csrf().disable()
    .authorizeRequests()
    .antMatchers(HttpMethod.OPTIONS, "/**").permitAll();

5. 踩坑四:CSRF 与前后端分离

Spring Security 默认开启 CSRF 防护,但在前后端分离架构下,很多接口会直接报 403。

解决方案: 如果系统主要基于 JWT / Token 认证,可以关闭 CSRF:

http.csrf().disable();

如果一定要用 CSRF,需要在前端请求中加上 _csrf token,这在大多数微服务项目中并不方便,因此通常会选择禁用。

1

6. 踩坑五:角色权限配置不生效

常见问题:

  • 已经给用户分配了角色,但访问接口还是报 403;

  • @PreAuthorize("hasRole('ADMIN')") 不生效。

根因:Spring Security 默认要求角色必须以 "ROLE_" 开头。

解决方案

  • 要么在数据库中保存 "ROLE_ADMIN" 这样的角色;

  • 要么在代码中自定义 GrantedAuthorityDefaults

@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
    return new GrantedAuthorityDefaults(""); // 去掉ROLE_前缀
}

7. 总结

结合踩坑经验,可以总结出几个 Spring Cloud Security 落地的最佳实践

  1. 统一认证中心:避免每个服务单独校验,减少冗余配置。

  2. JWT + Gateway 校验:让 Gateway 成为安全入口,服务内部只解析用户信息。

  3. Feign Token 透传:统一封装 RequestInterceptor,避免下游服务丢失身份。

  4. 开发环境与生产环境隔离:调试时可以开启简单模式,但生产必须接入认证中心。

  5. 关注版本差异:Spring Security 5.x 和 6.x 在配置上差异极大,迁移要谨慎。

Spring Cloud Security 给微服务带来了 可控的安全模型,但同时也增加了复杂性。 从认证、鉴权、跨域到服务调用,每一步都可能踩坑。

关键思路是:

  • 集中化(统一认证中心、统一网关入口);

  • 显式化(明确配置解码器、跨域策略、Token 透传);

  • 简化化(禁用不必要的 CSRF、统一角色前缀规则)。

这样才能真正建立一套稳定、安全、可维护的微服务安全体系。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐