Spring Security 登錄後重定向到不同頁面

Spring Security
Remote
1
07:01 PM · Nov 29 ,2025

1. 概述

一個常見的要求是,對於Web應用程序來説,在用户登錄後將不同類型的用户重定向到不同的頁面。例如,將標準用户重定向到 /homepage.html 頁面,而管理員用户則重定向到 /console.html 頁面。

本文將展示如何使用 Spring Security 快速且安全地實現此機制。本文還建立在 Spring MVC 教程的基礎上,該教程處理了項目所需的核心 MVC 設置。

2. The Spring Security Configuration

Spring Security 提供一個組件,負責在成功認證後執行的操作——AuthenticationSuccessHandler

2.1. Basic Configuration

首先配置一個基本的 @Configuration@Service類:

@Configuration
@EnableWebSecurity
public class SecSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            // ... endpoints
            .formLogin(formLogin -> formLogin.loginPage("/login.html")
                .loginProcessingUrl("/login")
                .defaultSuccessUrl("/homepage.html", true))
            // ... other configuration
        return http.build();
    }
}

該配置中的一部分是 defaultSuccessUrl方法。 在成功登錄後,任何用户都會重定向到 homepage.html

此外,我們需要配置用户及其角色。 為了本文的目的,我們將實現一個簡單的 UserDetailService,其中包含兩個用户,每個用户擁有一個單一角色。 關於此主題的更多信息,請閲讀我們的文章 Spring Security – Roles and Privileges。

@Service
public class MyUserDetailsService implements UserDetailsService {

    private Map<String, User> roles = new HashMap<>();

    @PostConstruct
    public void init() {
        roles.put("admin2", new User("admin", "{noop}admin1", getAuthority("ROLE_ADMIN")));
        roles.put("user2", new User("user", "{noop}user1", getAuthority("ROLE_USER")));
    }

    @Override
    public UserDetails loadUserByUsername(String username) {
        return roles.get(username);
    }

    private List<GrantedAuthority> getAuthority(String role) {
        return Collections.singletonList(new SimpleGrantedAuthority(role));
    }
}

請注意,在這個簡單的示例中,我們不會使用密碼編碼器,因此密碼前綴為 {noop}

2.2. Adding the Custom Success Handler

我們現在有兩個用户,擁有兩個不同的角色:useradmin。 在成功登錄後,兩者都會重定向到 hompeage.html讓我們看看如何根據用户的角色來設置不同的重定向。

首先,我們需要定義一個自定義成功處理程序作為 Bean:

@Bean
public AuthenticationSuccessHandler myAuthenticationSuccessHandler(){
    return new MySimpleUrlAuthenticationSuccessHandler();
}

然後將 defaultSuccessUrl調用替換為 successHandler方法,該方法接受自定義成功處理程序作為參數:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
        // endpoints
        .formLogin(formLogin -> formLogin.loginPage("/login.html")
            .loginProcessingUrl("/login")
            .successHandler(myAuthenticationSuccessHandler())
        // other configuration
    return http.build();
}

2.3. XML Configuration

在查看我們自定義成功處理程序的實現之前,讓我們也看一下 XML 配置:

<http use-expressions="true" >
    <!-- other configuration -->
    <form-login login-page='/login.html' 
      authentication-failure-url="/login.html?error=true"
      authentication-success-handler-ref="myAuthenticationSuccessHandler"/>
    <logout/>
</http>

<beans:bean id="myAuthenticationSuccessHandler"
  class="com.baeldung.security.MySimpleUrlAuthenticationSuccessHandler" />

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="user1" password="{noop}user1Pass" authorities="ROLE_USER" />
            <user name="admin1" password="{noop}admin1Pass" authorities="ROLE_ADMIN" />
        </user-service>
    </authentication-provider>
</authentication-manager>

3. 定製認證成功處理器

除了 AuthenticationSuccessHandler 接口,Spring 還提供了該策略組件的合理默認值——AbstractAuthenticationTargetUrlRequestHandler 和一個簡單的實現——SimpleUrlAuthenticationSuccessHandler。 通常,這些實現將確定登錄後 URL 並執行重定向到該 URL。

雖然這種機制具有一定的靈活性,但確定該目標 URL 的機制不允許通過編程方式進行確定——因此,我們將實現該接口並提供自定義處理器的實現。 此實現將根據用户角色確定重定向用户到登錄後的 URL。

首先,我們需要覆蓋 onAuthenticationSuccess 方法:

public class MySimpleUrlAuthenticationSuccessHandler
  implements AuthenticationSuccessHandler {

    protected Log logger = LogFactory.getLog(this.getClass());

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

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

        handle(request, response, authentication);
        clearAuthenticationAttributes(request);
    }

我們的自定義方法調用兩個輔助方法:

protected void handle(
        HttpServletRequest request,
        HttpServletResponse response, 
        Authentication authentication
) throws IOException {

    String targetUrl = determineTargetUrl(authentication);

    if (response.isCommitted()) {
        logger.debug(
                "Response has already been committed. Unable to redirect to "
                        + targetUrl);
        return;
    }

    redirectStrategy.sendRedirect(request, response, targetUrl);
}

其中,該方法執行實際工作並將用户映射到目標 URL:

protected String determineTargetUrl(final Authentication authentication) {

    Map<String, String> roleTargetUrlMap = new HashMap<>();
    roleTargetUrlMap.put("ROLE_USER", "/homepage.html");
    roleTargetUrlMap.put("ROLE_ADMIN", "/console.html");

    final Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
    for (final GrantedAuthority grantedAuthority : authorities) {
        String authorityName = grantedAuthority.getAuthority();
        if(roleTargetUrlMap.containsKey(authorityName)) {
            return roleTargetUrlMap.get(authorityName);
        }
    }

    throw new IllegalStateException();
}

請注意,此方法將返回第一個角色集合中給定的角色名稱對應的映射 URL。 因此,如果用户具有多個角色,映射 URL 將是第一個角色名稱匹配的映射 URL。

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

determineTargetUrl —— 策略的核心 —— 僅查看用户類型(通過權限確定)並根據該角色 選擇目標 URL。

因此,管理員用户——通過 ROLE_ADMIN 權限確定——將在登錄後重定向到控制枱頁面,而 標準用户——通過 ROLE_USER 確定——將重定向到主頁。

4. 結論

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.