Spring Security OAuth2授权登录后404,无法重定向至前端
解决Spring Security OAuth2表单登录后404及前端重定向问题
针对表单登录后无法重定向到http://localhost:5173/出现404的问题,结合后续社交登录的需求,以下是具体的修复和配置方案:
一、修正授权服务器的重定向URI白名单
首先要确保前端地址被加入授权服务器允许的重定向列表,授权码模式要求redirect_uri必须精确匹配(或配置通配符规则)。修改RegisteredClient配置:
@Bean public RegisteredClientRepository registeredClientRepository() { RegisteredClient frontendClient = RegisteredClient.withId(UUID.randomUUID().toString()) .clientId("frontend-client") .clientSecret("{noop}frontend-secret") // 生产环境替换为加密密码 .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) // 添加前端回调地址,支持授权码回调和首页跳转 .redirectUri("http://localhost:5173/login/oauth2/code/frontend-client") .redirectUri("http://localhost:5173/") .scope(OidcScopes.OPENID) .scope("read") .scope("write") .clientSettings(ClientSettings.builder().requireAuthorizationConsent(false).build()) .build(); return new InMemoryRegisteredClientRepository(frontendClient); }
二、调整表单登录后的跳转逻辑
表单登录成功后,需要引导用户完成OAuth2授权流程,而不是直接跳转前端。自定义AuthenticationSuccessHandler实现自动跳转授权端点:
@Bean public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); http.getConfigurer(OAuth2AuthorizationServerConfigurer.class).oidc(Customizer.withDefaults()); // 启用OIDC,为社交登录铺路 http .formLogin(form -> form .successHandler((request, response, auth) -> { // 从请求参数中获取授权所需的参数,跳转至授权端点 String redirectUri = request.getParameter("redirect_uri"); String clientId = request.getParameter("client_id"); String scope = request.getParameter("scope"); String state = request.getParameter("state"); String authUrl = String.format( "/oauth2/authorize?client_id=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s", clientId, URLEncoder.encode(redirectUri, StandardCharsets.UTF_8), scope, state ); response.sendRedirect(authUrl); }) ) .exceptionHandling(exceptions -> exceptions .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")) ); return http.build(); }
三、配置资源服务器跨域支持
前端和后端属于跨域场景,必须在资源服务器中配置CORS:
@Bean public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(List.of("http://localhost:5173")); config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); config.setAllowedHeaders(List.of("*")); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } // 资源服务器Security配置中启用CORS @Bean public SecurityFilterChain resourceServerSecurityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())) .cors(Customizer.withDefaults()); return http.build(); }
四、前端处理授权回调获取Token
前端需要在指定路径接收授权码,然后请求Token并保存。以Vue3为例:
路由配置
{ path: '/login/oauth2/code/frontend-client', component: () => import('../views/OAuth2Callback.vue') }
回调页面逻辑
<script setup> import { useRoute, useRouter } from 'vue-router'; import axios from 'axios'; const route = useRoute(); const router = useRouter(); const code = route.query.code; if (code) { axios.post('http://localhost:8080/oauth2/token', new URLSearchParams({ client_id: 'frontend-client', client_secret: 'frontend-secret', grant_type: 'authorization_code', code: code, redirect_uri: 'http://localhost:5173/login/oauth2/code/frontend-client' }), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).then(res => { localStorage.setItem('access_token', res.data.access_token); localStorage.setItem('refresh_token', res.data.refresh_token); router.push('/'); // 跳转到首页 }).catch(err => { console.error('Token获取失败:', err); router.push('/login'); }); } </script>
五、社交登录前置配置
如果后续要接入社交登录(如GitHub、Google),提前在授权服务器中启用OAuth2登录,并配置客户端信息:
// 在授权服务器SecurityFilterChain中添加 http .oauth2Login(oauth2 -> oauth2 .successHandler((request, response, auth) -> { // 社交登录成功后同样引导至授权端点,复用授权流程 String redirectUri = request.getParameter("redirect_uri"); String clientId = request.getParameter("client_id"); String scope = request.getParameter("scope"); String state = request.getParameter("state"); String authUrl = String.format( "/oauth2/authorize?client_id=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s", clientId, URLEncoder.encode(redirectUri, StandardCharsets.UTF_8), scope, state ); response.sendRedirect(authUrl); }) );
配置文件添加社交客户端信息(application.yml)
spring: security: oauth2: client: registration: github: client-id: 你的GitHub客户端ID client-secret: 你的GitHub客户端密钥 scope: read:user,user:email google: client-id: 你的Google客户端ID client-secret: 你的Google客户端密钥 scope: profile,email
404错误排查要点
- 查看日志确认404的具体请求路径,检查是否是重定向地址未加入授权服务器白名单。
- 确保授权服务器的
/login端点可正常访问,默认表单登录页面无需额外配置。 - 确认前后端端口无冲突,请求未发送到错误服务。
内容的提问来源于stack exchange,提问作者Kauã Pereira
相关产品推荐
相关产品推荐

