You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot OAuth2:实现指定微服务无认证访问受保护资源

嘿,这个需求在Spring Boot微服务的权限配置里挺常见的,我给你几个不同场景下的解决方案,你可以根据自己的部署环境和安全要求来选:

解决方案:让auth-service无需认证访问db-service的受保护接口

假设你的db-service已经集成了Spring Security来保护接口,核心思路就是在db-service的Security配置中,为auth-service的请求单独添加放行规则,同时保证其他请求依然处于受保护状态。

方法一:基于请求来源放行(适合固定环境)

如果auth-service和db-service部署在固定环境里(比如同一内网、K8s集群),可以直接针对auth-service的IP或者自定义服务标识来放行请求,既安全又精准:

  1. 在db-service的SecurityFilterChain配置类中添加规则:
@Configuration
@EnableWebSecurity
public class DbServiceSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                // 方式1:根据auth-service的固定IP放行(比如本地测试的127.0.0.1,或者内网IP)
                .requestMatchers("/api/users/**").hasIpAddress("127.0.0.1")
                // 方式2:根据自定义请求头标识放行(推荐微服务集群使用)
                .requestMatchers("/api/users/**").hasHeader("X-Service-Name", "auth-service")
                // 其他所有请求必须认证
                .anyRequest().authenticated()
            )
            // 保留你原本的认证方式,比如JWT、Basic Auth等
            .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
        return http.build();
    }
}
  1. auth-service调用时记得带上对应的请求头(如果用header方式):
@Service
public class DbServiceClient {
    private final RestTemplate restTemplate;

    public DbServiceClient(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public User getUserByUsername(String username) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("X-Service-Name", "auth-service");
        HttpEntity<Void> entity = new HttpEntity<>(headers);
        return restTemplate.exchange(
            "http://db-service:8002/api/users/{username}",
            HttpMethod.GET,
            entity,
            User.class,
            username
        ).getBody();
    }
}

方法二:直接放行特定接口(适合完全信任的测试环境)

如果你的环境是完全封闭、内部完全信任的,也可以直接放行db-service中那个查询用户的接口,不需要验证来源:

@Configuration
@EnableWebSecurity
public class DbServiceSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                // 直接放行查询用户的接口
                .requestMatchers("/api/users/{username}").permitAll()
                // 其他接口依然受保护
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
        return http.build();
    }
}

⚠️ 敲黑板:这种方式要谨慎用!只要知道接口地址的客户端都能访问,只适合内部测试或者完全封闭的环境。

方法三:服务间认证(生产环境最佳实践)

如果是生产环境,更推荐用OAuth2客户端凭证模式做服务间认证,既保证安全性,又能实现可控的服务间访问:

  1. 在db-service的Security配置中,开启资源服务器并指定权限范围:
@Configuration
@EnableWebSecurity
public class DbServiceSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                // 只允许带有internal权限的请求访问该接口
                .requestMatchers("/api/users/**").hasAuthority("SCOPE_internal")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
        return http.build();
    }
}
  1. 在auth-service中配置OAuth2客户端,获取访问db-service的凭证:
# auth-service的application.yml
spring:
  security:
    oauth2:
      client:
        registration:
          db-service-client:
            client-id: auth-service-client
            client-secret: your-secure-secret
            authorization-grant-type: client_credentials
            scope: internal
        provider:
          db-service-provider:
            token-uri: http://your-auth-center:8001/oauth2/token # 填统一认证中心的token地址,或者db-service自身的token端点
  1. auth-service调用时自动携带认证token:
@Service
public class DbServiceClient {
    private final OAuth2AuthorizedClientService authorizedClientService;
    private final RestTemplate restTemplate;

    public DbServiceClient(OAuth2AuthorizedClientService authorizedClientService, RestTemplate restTemplate) {
        this.authorizedClientService = authorizedClientService;
        this.restTemplate = restTemplate;
    }

    public User getUserByUsername(String username) {
        OAuth2AuthorizedClient client = authorizedClientService.loadAuthorizedClient(
            "db-service-client",
            "client-credentials"
        );
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(client.getAccessToken().getTokenValue());
        HttpEntity<Void> entity = new HttpEntity<>(headers);
        return restTemplate.exchange(
            "http://db-service:8002/api/users/{username}",
            HttpMethod.GET,
            entity,
            User.class,
            username
        ).getBody();
    }
}

这种方式是生产环境的标准做法,既能防止未授权访问,又能清晰管控服务间的权限。


内容的提问来源于stack exchange,提问作者t.piwowarczyk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:11:11