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

微服务架构下Google OAuth登录404问题求助

问题描述

采用微服务架构,API-GATEWAY运行在9090端口,login service运行在8082端口。尝试通过Google OAuth进行认证时,请求可正确转发至login service,但该服务将Google OAuth登录URL识别为静态路径资源,返回404错误。

相关Security配置代码

package com.example.login.Security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.example.login.Service.CustomUserService;
import com.example.login.oauth.config.OAuth2LoginFailureHandler;
import com.example.login.oauth.config.OAuth2LoginSuccessHandler;

import jakarta.servlet.http.HttpServletRequest;

@Configuration
public class AppConfig {

    @Autowired
    private JwtAuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    private JwtTokenValidattor jwtTokenValidator;

    @Autowired
    private CustomUserService customUserService;

    @Autowired
    private OAuth2LoginSuccessHandler oAuth2LoginSuccessHandler;
    @Autowired
    private OAuth2LoginFailureHandler oAuth2LoginFailureHandler;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;
    private final String[] PUBLIC_URL = { "/login/jwt", "/login/register", "/login/api/payment/create",
            "/login/api/payment/update", "/swagger-ui.html", "/swagger-ui/**", "/v3/api-docs/**", "/user/fetch/qrdata",
            "/oauth2/**", "/login/oauth2/**", "/login/oauth2/authorization/google" };

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.cors(Customizer.withDefaults()).csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(
                        (auth) -> auth.requestMatchers(PUBLIC_URL).permitAll().anyRequest().authenticated())
                .oauth2Login(oauth -> oauth.successHandler(oAuth2LoginSuccessHandler)
                        .failureHandler(oAuth2LoginFailureHandler))
                .exceptionHandling((ex) -> ex.authenticationEntryPoint(this.authenticationEntryPoint))
                .sessionManagement((s) -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        http.authenticationProvider(authenticationProvider());
        http.addFilterBefore(this.jwtTokenValidator, UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore((request, response, chain) -> {
            if (request instanceof HttpServletRequest) {
                HttpServletRequest httpRequest = (HttpServletRequest) request;
                System.out.println("Request URL : " + httpRequest.getRequestURI());

            }
            chain.doFilter(request, response);
        }, UsernamePasswordAuthenticationFilter.class);
        DefaultSecurityFilterChain defaultSecurityFilterChain = http.build();
        return defaultSecurityFilterChain;
    }

    @Bean
    public AuthenticationManager authenticationManagerBean(AuthenticationConfiguration authenticationConfiguration)
            throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(this.customUserService);
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
        return daoAuthenticationProvider;
    }

    @Bean
    public OidcUserService oidService() {
        return new OidcUserService();
    }
}

相关OAuth2客户端配置代码

package com.example.login.oauth.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;

import com.example.login.Security.JWTConstant;

@Configuration
public class OAuth2ClientConfig {

    @Value("${app.base-url}") 
    private String baseUrl;

    @Bean
    public ClientRegistrationRepository clientRegistrationRepository() {
        return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
    }

    private ClientRegistration googleClientRegistration() {
        return ClientRegistration.withRegistrationId(JWTConstant.GOOGLE_REGISTRATION_ID)
                .clientId(JWTConstant.GOOGLE_CLIENT_ID)
                .clientSecret(JWTConstant.GOOGLE_CLIENT_SECRET)
                .redirectUri(baseUrl + JWTConstant.GOOGLE_REDIRECT_URI_SUFFIX)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .scope(JWTConstant.GOOGLE_SCOPE)
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
                .authorizationUri(JWTConstant.GOOGLE_AUTHORISATION_URL)
                .tokenUri(JWTConstant.GOOGLE_TOKEN_URI)
                .userInfoUri(JWTConstant.GOOGLE_USER_INFO_URI)
                .userNameAttributeName(JWTConstant.ATTRIBUTE_NAME)
                .clientName(JWTConstant.GOOGLE_CLIENT_NAME)
                .build();
    }
}

错误日志

Request URL : /login/oauth2/authorization/google
2024-10-08T16:42:54.705+05:30 DEBUG 21452 --- [login-service] [nio-8082-exec-2] o.s.web.servlet.DispatcherServlet        : GET "/login/oauth2/authorization/google", parameters={}
2024-10-08T16:42:54.717+05:30 DEBUG 21452 --- [login-service] [nio-8082-exec-2] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped to ResourceHttpRequestHandler [classpath [META-INF/resources/], classpath [resources/], classpath [static/], classpath [public/], ServletContext [/]]
2024-10-08T16:42:54.732+05:30 DEBUG 21452 --- [login-service] [nio-8082-exec-2] o.s.w.s.r.ResourceHttpRequestHandler     : Resource not found
2024-10-08T16:42:54.737+05:30 DEBUG 21452 --- [login-service] [nio-8082-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.servlet.resource.NoResourceFoundException: No static resource login/oauth2/authorization/google.]
2024-10-08T16:42:54.738+05:30 DEBUG 21452 --- [login-service] [nio-8082-exec-2] o.s.web.servlet.DispatcherServlet        : Completed 404 NOT_FOUND
解决方案

问题核心是路径前缀不匹配、无状态会话与OAuth2流程冲突,按以下步骤修复:

  1. 配置OAuth2端点的基础路径
    Spring Security默认OAuth2授权端点是/oauth2/authorization/google,但请求带了/login前缀,导致Security无法识别内置处理逻辑。在SecurityFilterChain的oauth2Login配置中添加baseUri:
.oauth2Login(oauth -> oauth.baseUri("/login/oauth2") // 匹配带前缀的OAuth2路径
        .successHandler(oAuth2LoginSuccessHandler)
        .failureHandler(oAuth2LoginFailureHandler))
  1. 调整会话策略
    OAuth2授权码流程需要会话存储授权请求状态,STATELESS配置会破坏这一机制。修改会话策略为按需创建:
.sessionManagement((s) -> s.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED))

若需保留其他接口无状态,可针对OAuth2路径单独配置会话规则。

  1. 清理冗余配置
    PUBLIC_URL中已包含/login/oauth2/**,删除重复的/login/oauth2/authorization/google条目,避免配置混乱。

  2. 校验网关路由
    确认网关转发规则:如果网关将/login/**转发到login service的/login/**,则上述配置正确;如果是转发到/**,则需将login service中的OAuth2路径改为/oauth2/**,同步调整PUBLIC_URL和oauth2Login的baseUri。


内容的提问来源于stack exchange,提问作者Mohit Patel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 10:39:52