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

OAuth2授权后如何从重定向URI中移除/api上下文路径

移除OAuth2授权重定向URI中的/api上下文路径解决方案

问题分析

你的应用配置了/api上下文路径,Spring Security OAuth2默认会将该路径包含在授权回调URI和授权成功后的重定向地址中,导致前端跳转错误。需要同时调整OAuth2客户端的回调URI配置和授权成功后的重定向逻辑,才能实现动态跳转回去除/api前缀的原页面。

解决方案步骤

1. 调整OAuth2客户端注册的重定向URI

在application.properties中显式指定不带/api前缀的授权回调URI,覆盖Spring Security的默认生成逻辑:

# 新增配置:指定不带/api的回调URI
spring.security.oauth2.client.registration.keycloak.redirect-uri=http://localhost:8080/login/oauth2/code/keycloak

# 原有配置保持不变
spring.security.oauth2.client.registration.keycloak.client-id=myClientId
spring.security.oauth2.client.registration.keycloak.client-secret=myClientSecret
spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8080/realms/master
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8080/realms/master
spring.security.oauth2.client.registration.keycloak.scope=openid
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username

2. 在Keycloak控制台更新允许的重定向URI

进入Keycloak控制台,找到你的myClientId客户端:

  • 切换到Valid Redirect URIs配置项
  • 添加http://localhost:8080/login/oauth2/code/keycloak到允许列表中
  • 若仍需要支持带/api的回调,可保留原有http://localhost:8080/api/login/oauth2/code/keycloak

3. 自定义OAuth2授权成功处理器,动态调整重定向地址

修改Spring Security配置,添加自定义的AuthenticationSuccessHandler,从授权请求中获取原跳转地址并移除/api前缀:

import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRepository;
import org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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 javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final OAuth2AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository =
            new HttpSessionOAuth2AuthorizationRequestRepository();

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers(matchers).permitAll()
                        .anyRequest().authenticated()
                )
                .httpBasic().disable()
                .anonymous().disable()
                .oauth2Login(oauth2 -> oauth2
                        .authorizationRequestRepository(authorizationRequestRepository)
                        .successHandler(customOAuth2SuccessHandler()) // 绑定自定义成功处理器
                )
                .logout(logout -> logout
                        .logoutSuccessHandler(oidcLogoutSuccessHandler()))
                .oauth2ResourceServer(resource -> resource.jwt());

        return http.build();
    }

    // 自定义授权成功处理器:移除重定向地址中的/api前缀
    private AuthenticationSuccessHandler customOAuth2SuccessHandler() {
        return (request, response, authentication) -> {
            OAuth2AuthorizationRequest authRequest = authorizationRequestRepository.loadAuthorizationRequest(request);
            if (authRequest != null && authRequest.getRedirectUri() != null) {
                String originalTargetUrl = authRequest.getRedirectUri();
                // 替换/api前缀为空,保留后续路径
                String adjustedTargetUrl = originalTargetUrl.replaceFirst("^http://localhost:8080/api", "http://localhost:8080");
                response.sendRedirect(adjustedTargetUrl);
                return;
            }
            // 兜底跳转至根路径
            response.sendRedirect("http://localhost:8080/");
        };
    }

    // 保留原有登出处理器实现
    private LogoutSuccessHandler oidcLogoutSuccessHandler() {
        // 你的原有登出逻辑代码
        return null; // 替换为实际实现
    }
}

原理说明

  • 显式指定redirect-uri让OAuth2回调直接指向不带/api的地址,避免Keycloak回调到/api路径
  • 自定义成功处理器通过OAuth2AuthorizationRequestRepository获取用户发起授权前的目标地址,动态去除/api前缀后跳转,实现动态回跳需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 13:10:18