Redirect to Different Pages after Login with Spring Security – 用Spring Security登录后重定向到不同页面

最后修改: 2013年 7月 14日

1. Overview

1.概述

A common requirement for a web application is to redirect different types of users to different pages after login. An example of this would be redirecting standard users to a /homepage.html page and admin users to a /console.html page for example.

网络应用程序的一个常见要求是在登录后将不同类型的用户重定向到不同页面。例如,将标准用户重定向到/homepage.html页面,将管理员用户重定向到/console.html页面。

This article will show how to quickly and safely implement this mechanism using Spring Security. The article is also building on top of the Spring MVC tutorial which deals with setting up the core MVC stuff necessary for the project.

本文将介绍如何使用Spring Security快速、安全地实现这一机制。本文也是建立在Spring MVC 教程的基础上,该教程涉及设置项目所需的核心 MVC 东西。

2. The Spring Security Configuration

2.Spring安全配置

Spring Security provides a component that has the direct responsibility of deciding what to do after a successful authentication – the AuthenticationSuccessHandler.

Spring Security提供了一个组件,直接负责决定在认证成功后做什么–AuthenticationSuccessHandler

2.1. Basic Configuration

2.1.基本配置

Let’s first configure a basic @Configuration and @Service class:

让我们首先配置一个基本的@Configuration@Service类。

@Configuration
@EnableWebSecurity
public class SecSecurityConfig {

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

The part of this configuration to focus on is the defaultSuccessUrl() method. After a successful login, any user will be redirected to homepage.html.

这个配置中需要关注的部分是defaultSuccessUrl()方法。登录成功后,任何用户都将被重定向到homepage.html

Furthermore, we need to configure users and their roles. For the purpose of this article, we’ll implement a simple UserDetailService with two users, each having one single role. For more on this topic, read our article Spring Security – Roles and Privileges.

此外,我们还需要配置用户和他们的角色。为了这篇文章的目的,我们将实现一个简单的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));
    }
}

Also note that in this simple example, we won’t use a password encoder, therefore the passwords are prefixed with {noop}.

还要注意,在这个简单的例子中,我们不会使用密码编码器,因此密码的前缀是{noop}

2.2. Adding the Custom Success Handler

2.2.添加自定义成功处理程序

We now have two users with the two different roles: user and admin. After a successful login, both will be redirected to hompeage.html. Let’s look at how we can have a different redirect based on the user’s role.

我们现在有两个具有两种不同角色的用户。用户管理员。在成功登录后,两人都将被重定向到hompeage.html让我们来看看如何根据用户的角色来进行不同的重定向。

First, we need to define a custom success handler as a bean:

首先,我们需要将一个自定义的成功处理程序定义为一个bean。

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

And then replace the defaultSuccessUrl call with the successHandler method, which accepts our custom success handler as a parameter:

然后用successHandler方法替换defaultSuccessUrl调用,该方法接受我们的自定义成功处理器作为参数。

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

2.3. XML Configuration

2.3. XML配置

Before looking at the implementation of our custom success handler, let’s also look at the equivalent 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. The Custom Authentication Success Handler

3.自定义认证成功处理程序

Besides the AuthenticationSuccessHandler interface, Spring also provides a sensible default for this strategy component – the AbstractAuthenticationTargetUrlRequestHandler and a simple implementation – the SimpleUrlAuthenticationSuccessHandler. Typically these implementations will determine the URL after login and perform a redirect to that URL.

除了AuthenticationSuccessHandler接口,Spring还为这个策略组件提供了一个合理的默认值–AbstractAuthenticationTargetUrlRequestHandler和一个简单实现–SimpleUrlAuthenticationSuccessHandler。通常,这些实现将在登录后确定URL,并执行重定向到该URL。

While somewhat flexible, the mechanism to determine this target URL does not allow the determination to be done programmatically – so we’re going to implement the interface and provide a custom implementation of the success handler. This implementation is going to determine the URL to redirect the user to after login based on the role of the user. 

虽然有一定的灵活性,但确定这个目标URL的机制不允许以编程方式进行确定 – 所以我们要实现这个接口,并提供一个自定义的成功处理程序的实现。该实现将根据用户的角色来确定用户在登录后重定向到的 URL。

First of all, we need to override the onAuthenticationSuccess method:

首先,我们需要覆盖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);
    }

Our customized method calls two helper methods:

我们的定制方法调用了两个辅助方法。

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);
}

Where the following method does the actual work and maps the user to the target URL:

而下面的方法做实际工作,将用户映射到目标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();
}

Note that this method will return the mapped URL for the first role the user has. So if a user has multiple roles, the mapped URL will be the one that matches the first role given in the authorities collection.

注意,这个方法将返回用户拥有的第一个角色的映射URL。因此,如果一个用户有多个角色,映射的URL将是与authorities集合中给出的第一个角色相匹配的那个。

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

The determineTargetUrl – which is the core of the strategy – simply looks at the type of user (determined by the authority) and picks the target URL based on this role.

determineTargetUrl–这是策略的核心–简单地看一下用户的类型(由权限决定),并根据这个角色挑选目标URL

So, an admin user – determined by the ROLE_ADMIN authority – will be redirected to the console page after login, while the standard user – as determined by ROLE_USER – will be redirected to the homepage.

因此,管理员用户–由ROLE_ADMIN权限决定–在登录后将被重定向到控制台页面,而标准用户–由ROLE_USER决定–将被重定向到主页上。

4. Conclusion

4.结论

As always, the code presented in this article is available over on GitHub. This is a Maven-based project, so it should be easy to import and run as it is.

像往常一样,本文介绍的代码可以在GitHub上找到over。这是一个基于Maven的项目,所以应该很容易导入并按原样运行。