微服务架构下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流程冲突,按以下步骤修复:
- 配置OAuth2端点的基础路径
Spring Security默认OAuth2授权端点是/oauth2/authorization/google,但请求带了/login前缀,导致Security无法识别内置处理逻辑。在SecurityFilterChain的oauth2Login配置中添加baseUri:
.oauth2Login(oauth -> oauth.baseUri("/login/oauth2") // 匹配带前缀的OAuth2路径 .successHandler(oAuth2LoginSuccessHandler) .failureHandler(oAuth2LoginFailureHandler))
- 调整会话策略
OAuth2授权码流程需要会话存储授权请求状态,STATELESS配置会破坏这一机制。修改会话策略为按需创建:
.sessionManagement((s) -> s.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED))
若需保留其他接口无状态,可针对OAuth2路径单独配置会话规则。
清理冗余配置
PUBLIC_URL中已包含/login/oauth2/**,删除重复的/login/oauth2/authorization/google条目,避免配置混乱。校验网关路由
确认网关转发规则:如果网关将/login/**转发到login service的/login/**,则上述配置正确;如果是转发到/**,则需将login service中的OAuth2路径改为/oauth2/**,同步调整PUBLIC_URL和oauth2Login的baseUri。
内容的提问来源于stack exchange,提问作者Mohit Patel
相关产品推荐
相关产品推荐

