如何从FormLoginConfigurer中提取loginPage等配置URL?
提取FormLoginConfigurer配置的URL并在SuccessHandler中使用
以下是两种可行的实现方案,优先推荐第一种低耦合、易维护的方式:
方案1:提取URL为常量并注入到SuccessHandler
将配置的URL统一抽成常量,既避免硬编码重复,又能让SuccessHandler直接获取到目标值:
- 在
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(); } }
- 修改
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,版本升级可能存在变动:
- 在
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(); }
- 在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
相关产品推荐
相关产品推荐

