普通 SpringBoot 单体项目改造成微服务(Nacos+Gateway + 内部服务免鉴权)
摘要
本文详细介绍如何将普通 SpringBoot 单体项目改造为微服务架构。涵盖 Nacos 服务注册发现、Gateway 网关路由配置、微服务内部信任免鉴权完整实现方案,同时解决改造过程中 401 未授权、循环依赖、过滤器优先级冲突等常见坑。
关键词
SpringBoot 微服务改造;Nacos;Spring Cloud Gateway;微服务内部免鉴权;SpringSecurity
🔥 前言
日常开发中很多项目都是从SpringBoot 单体应用起步,随着业务模块增多、并发量提升、团队协作复杂化,单体架构的弊端逐渐凸显:
- 所有功能打包部署,改动需全量发布,风险高
- 无法针对核心模块单独扩容
- 无统一请求入口,接口直接暴露外网不安全
因此,将单体 SpringBoot 项目改造为微服务是架构演进的必经之路。
本文基于通用生产落地经验,从零完成整套微服务改造:
- SpringBoot 整合 Nacos 实现服务注册与发现
- Gateway 网关实现路由转发、路径重写、负载均衡
- 微服务内部建立信任通道,实现网关请求免登录、免 Token、免鉴权
- 规避 401 未授权、循环依赖、过滤器冲突等经典问题
📌 目录
- 环境版本说明
- 引入 Nacos 微服务依赖
- 项目配置 Nacos 注册中心
- Gateway 网关路由核心配置
- 后端自定义网关内部信任过滤器
- SpringSecurity 整合过滤器配置
- 可选扩展:网关透传账号自动登录
- 接口调用效果验证
- 改造常见问题与避坑总结
- 改造整体架构小结
一、环境版本说明
- 框架版本:SpringBoot 3.x
- 微服务版本:Spring Cloud Alibaba 适配 SpringBoot3 稳定版
- 注册中心:Nacos 2.x
- 网关组件:Spring Cloud Gateway
- 安全框架:Spring Security 6.x
二、引入 Nacos 微服务依赖
在pom.xml中引入 Spring Cloud Alibaba 版本管理和 Nacos 注册发现依赖,统一版本避免框架冲突。
xml
<dependencies>
<!-- Nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<!-- Spring Cloud 版本管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2023.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2023.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
三、项目配置 Nacos 注册中心
在application.yml配置文件中添加 Nacos 基础配置。
yaml
spring:
application:
name: business-service # 自定义微服务名称,网关路由依赖此名称
cloud:
nacos:
discovery:
# 替换为自己的Nacos服务地址
server-addr: 127.0.0.1:8848
# 自定义命名空间,保持网关和微服务统一即可
namespace: public
# 脱敏默认账号密码,自行修改
username: nacos
password: nacos
# 开启服务注册与发现
enabled: true
register-enabled: true
配置完成启动项目,可在 Nacos 控制台「服务管理 - 服务列表」查看服务注册状态。
四、Gateway 网关路由核心配置
网关作为微服务统一入口,负责请求路由、负载均衡、路径重写、透传内部秘钥,收口外网所有请求,保护后端服务不暴露公网。
yaml
spring:
cloud:
# 网关配置
gateway:
# 开启请求日志
requestLog: true
discovery:
locator:
lowerCaseServiceId: true
enabled: true
# 路由规则配置
routes:
- id: business-service-route
# lb代表负载均衡,从Nacos拉取服务实例
uri: lb://business-service
predicates:
- Path=/business/**
filters:
# 路径重写:前端 /business/xxx 转发到服务 /xxx
- RewritePath=/business/(?<path>.*), /$\{path}
# 固定内部通信秘钥,微服务间信任凭证
- name: SetRequestHeader
args:
name: X-Internal-Gateway-Secret
value: Gateway@MicroService2026
核心作用:
- 所有请求统一经过网关,后端服务仅内网可见
- 基于 Nacos 自动实现负载均衡、服务实例感知
- 自动透传固定秘钥请求头,作为微服务内部信任标识
五、后端自定义网关内部信任过滤器
微服务改造最大痛点:网关转发的内部接口,仍被 SpringSecurity 拦截抛出 401。
自定义全局过滤器,识别网关透传的合法秘钥,若业务需要网关前置完成用户登录,后端直接复用身份 ,可改造过滤器接收自定义账号请求头,自动完成系统登录认证,无需校验密码。不需要的话则直接授予系统认证权限,免登录、免 Token、免业务鉴权。
java
package com.xxx.business.auth.filter;
import com.iflytek.skillhub.auth.rbac.PlatformPrincipal;
import com.iflytek.skillhub.auth.session.PlatformSessionService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import com.iflytek.skillhub.auth.local.LocalAuthService;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
public class InternalAuthFilter extends OncePerRequestFilter {
public static final String INTERNAL_SECRET = "SkillHub@2026RuoYiCloud";
public static final String HEADER_NAME = "X-Internal-SkillHub-Secret";
private final LocalAuthService localAuthService;
private final PlatformSessionService platformSessionService;
public InternalAuthFilter(LocalAuthService localAuthService, PlatformSessionService platformSessionService) {
this.localAuthService = localAuthService;
this.platformSessionService = platformSessionService;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
String secret = request.getHeader(HEADER_NAME);
String userName = request.getHeader("userName");
String password = request.getHeader("password");
if (INTERNAL_SECRET.equals(secret) && userName != null && password != null) {
try {
//调用服务中的登录接口进行登录认证
PlatformPrincipal principal = localAuthService.login(userName, password);
platformSessionService.establishSession(principal, request);
List<SimpleGrantedAuthority> authorities = principal.platformRoles() == null
? Collections.emptyList()
: principal.platformRoles().stream()
.map(r -> new SimpleGrantedAuthority("ROLE_" + r))
.toList();
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
principal, null, authorities
);
SecurityContextHolder.getContext().setAuthentication(auth);
System.out.println("=== 网关自动登录成功:" + userName + " ===");
} catch (Exception e) {
System.err.println("网关登录失败:" + e.getMessage());
}
}
filterChain.doFilter(request, response);
}
}
六、SpringSecurity 整合过滤器配置
在SecurityConfig配置类中,手动 Bean 注入过滤器,不加 @Component 规避循环依赖,同时调整过滤器优先级,保证最先执行。
java
package com.xxx.business.auth.config;
import com.xxx.business.auth.filter.InternalGatewayAuthFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import static com.xxx.business.auth.filter.InternalGatewayAuthFilter.HEADER_NAME;
import static com.xxx.business.auth.filter.InternalGatewayAuthFilter.INTERNAL_SECRET;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
// 手动创建过滤器Bean,规避循环依赖
@Bean
public InternalGatewayAuthFilter internalGatewayAuthFilter() {
return new InternalGatewayAuthFilter();
}
/**
* 核心配置:过滤器顺序 + 放行规则
*/
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, InternalGatewayAuthFilter internalGatewayAuthFilter) throws Exception {
http
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.csrfTokenRequestHandler(csrfHandler)
.ignoringRequestMatchers(csrfIgnoreMatcher)
)
// 权限配置(正确合并版)
.authorizeHttpRequests(auth -> {
// 网关带密钥的请求 → 直接放行
auth.requestMatchers(request ->
INTERNAL_SECRET.equals(request.getHeader(HEADER_NAME))
).permitAll();
// 加载系统原有路由放行规则(如登录接口、静态资源等)
configureRoutePolicies(auth);
// 其他所有请求必须认证
auth.anyRequest().authenticated();
})
// 关键:把内部过滤器放在最前面
.addFilterBefore(internalGatewayAuthFilter, UsernamePasswordAuthenticationFilter.class)
return http.build();
}
private void configureRoutePolicies(org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry auth) {
for (RouteSecurityPolicyRegistry.RouteAuthorizationPolicy policy : routeSecurityPolicyRegistry.authorizationPolicies()) {
switch (policy.accessLevel()) {
case PERMIT_ALL -> auth.requestMatchers(policy.toRequestMatcher()).permitAll();
case AUTHENTICATED -> auth.requestMatchers(policy.toRequestMatcher()).authenticated();
case ROLE_PROTECTED -> auth.requestMatchers(policy.toRequestMatcher()).hasAnyRole(policy.roles());
}
}
}
}
七、接口调用效果验证
Postman 测试方式:
- 请求地址:
GET /business/api/xxx/xxx - 请求头:
X-Internal-Gateway-Secret: Gateway@MicroService2026
调用结果:
- 无需携带 Token、无需页面登录
- 接口直接 200 正常返回业务数据
- 控制台打印网关放行日志
八、改造常见问题与避坑总结
1、接口 401 未授权
- 网关未配置透传内部秘钥请求头
- 过滤器优先级过低,被 Token 认证过滤器覆盖
- 前后端秘钥字符、大小写不一致
2、多过滤器执行冲突
- 不使用
@Order注解控制优先级 - 依靠 SpringSecurity 的
addFilterBefore手动指定执行顺序
3、Nacos 服务注册失败
- Spring Cloud Alibaba 与 SpringBoot 版本不匹配
- 命名空间、服务名称配置不一致
- 服务器网络不通,无法访问 Nacos 注册中心
九、改造整体架构小结
通过以上通用方案,可快速完成普通 SpringBoot 单体 → 标准微服务架构改造:
- 接入 Nacos 实现服务注册、发现与服务治理
- Gateway 统一网关入口,实现路由转发、负载均衡
- 基于私有秘钥建立微服务内部信任通道,内部接口免鉴权
- 兼容原有 SpringSecurity 登录体系,无侵入业务代码
- 规避改造中 401、循环依赖、过滤器冲突等经典问题