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

如何从FormLoginConfigurer中提取loginPage等配置URL?

提取FormLoginConfigurer配置的URL并在SuccessHandler中使用

以下是两种可行的实现方案,优先推荐第一种低耦合、易维护的方式:

方案1:提取URL为常量并注入到SuccessHandler

将配置的URL统一抽成常量,既避免硬编码重复,又能让SuccessHandler直接获取到目标值:

  1. 在WebSecurityConfig中定义常量并复用:
public class WebSecurityConfig {
    // 统一管理FormLogin相关URL常量
    public static final String LOGIN_PAGE = "/login";
    public static final String LOGIN_PROCESSING_URL = "/authenticate";
    public static final String FAILURE_URL = "/login?error";

    @Bean
    public SecurityFilterChain defaultFilterChain(HttpSecurity http) throws Exception {
        return http
                .authorizeRequests(auth -> auth
                        .mvcMatchers("/").permitAll()
                        .mvcMatchers("/**").authenticated())
                .formLogin(login -> login
                        .loginPage(LOGIN_PAGE)
                        .loginProcessingUrl(LOGIN_PROCESSING_URL)
                        .failureUrl(FAILURE_URL)
                        .successHandler(new CustomAuthenticationSuccessHandler(LOGIN_PAGE, FAILURE_URL)) // 传入常量
                        .permitAll())
                .build();
    }
}
  1. 修改CustomAuthenticationSuccessHandler,通过构造函数接收URL:
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    private final String loginPage;
    private final String failureUrl;

    // 构造函数注入URL参数
    public CustomAuthenticationSuccessHandler(String loginPage, String failureUrl) {
        this.loginPage = loginPage;
        this.failureUrl = failureUrl;
    }

    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication) throws IOException {
        handleRedirect(request, response, authentication);
        clearAuthenticationAttributes(request);
    }

    private void handleRedirect(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication) throws IOException {
        String targetUrl = determineTargetUrl(request, authentication);
        if (response.isCommitted()) return;
        redirectStrategy.sendRedirect(request, response, targetUrl);
    }

    private String determineTargetUrl(HttpServletRequest request, Authentication authentication) {
        Set<String> authorities = authentication.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.toSet());
        
        SavedRequest savedRequest = (SavedRequest) request.getSession()
                .getAttribute("SPRING_SECURITY_SAVED_REQUEST");

        // 直接使用注入的URL做业务判断
        if (authorities.contains("ROLE_ADMIN")) return "/admin";
        if (authorities.contains("ROLE_USER")) {
            // 示例:判断跳转目标是否和登录页相关
            if (savedRequest != null && savedRequest.getRedirectUrl().contains(loginPage)) {
                return "/user/dashboard";
            }
            return savedRequest.getRedirectUrl();
        }

        throw new IllegalStateException();
    }

    private void clearAuthenticationAttributes(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) return;
        session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
    }
}

方案2:通过Spring Security配置对象获取(进阶)

如果不想硬编码常量,可直接从FormLogin配置对象中读取值,但该方式依赖Spring Security内部API,版本升级可能存在变动:

  1. 在WebSecurityConfig中暴露FormLogin配置:
@Bean
public FormLoginConfigurer<HttpSecurity> formLoginConfigurer() {
    return new FormLoginConfigurer<HttpSecurity>()
            .loginPage("/login")
            .loginProcessingUrl("/authenticate")
            .failureUrl("/login?error")
            .permitAll();
}

@Bean
public SecurityFilterChain defaultFilterChain(HttpSecurity http, FormLoginConfigurer<HttpSecurity> formLoginConfigurer) throws Exception {
    return http
            .authorizeRequests(auth -> auth
                    .mvcMatchers("/").permitAll()
                    .mvcMatchers("/**").authenticated())
            .apply(formLoginConfigurer)
            .successHandler(new CustomAuthenticationSuccessHandler(formLoginConfigurer))
            .and()
            .build();
}
  1. 在SuccessHandler中读取配置值:
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    private final String loginPage;
    private final String loginProcessingUrl;
    private final String failureUrl;

    public CustomAuthenticationSuccessHandler(FormLoginConfigurer<HttpSecurity> configurer) {
        this.loginPage = configurer.getLoginPage();
        this.loginProcessingUrl = configurer.getLoginProcessingUrl();
        this.failureUrl = configurer.getFailureUrl();
    }

    // 后续方法同前,可直接使用上述变量
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 03:55:28