Redirecting Logged-in Users with Spring Security – 用Spring Security重定向已登录的用户

最后修改: 2020年 6月 20日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

It’s common for websites to keep their users from visiting the login when they are already logged in. A common way to do that is to redirect the user to another page, usually the starting point of the application after logging in.

对于网站来说,当用户已经登录时,不让他们访问登录是很常见的。一个常见的方法是将用户重定向到另一个页面,通常是登录后的应用程序的起点。

In this tutorial, we’ll explore multiple ways to implement this solution using Spring Security.

在本教程中,我们将探讨使用Spring Security实现这一解决方案的多种方法。

Also, to learn more about how we can quickly implement a login, we can start with this article.

另外,要了解更多关于如何快速实现登录的信息,我们可以从这篇文章开始。

2. Authentication Verification

2.认证核查

First, we’ll need a method to verify the authentication.

首先,我们需要一种方法来验证认证。

In other words, we’ll need to get the authentication details from the SecurityContext and verify if the user is logged in:

换句话说,我们需要从SecurityContext中获取认证细节,并验证用户是否已登录

private boolean isAuthenticated() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (authentication == null || AnonymousAuthenticationToken.class.
      isAssignableFrom(authentication.getClass())) {
        return false;
    }
    return authentication.isAuthenticated();
}

We’ll use this in all the following components that are responsible for the redirection.

我们将在以下所有负责重定向的组件中使用它。

3. Redirecting from the Login Controller

3.从登录控制器重定向

The simplest way to achieve our goal is to define an endpoint for the login page in a controller.

实现我们目标的最简单方法是在控制器中为登录页面定义一个端点。

We’ll also need to return a specific page if the user is authenticated and the login page otherwise:

如果用户通过了认证,我们还需要返回一个特定的页面,否则就返回登录页面。

@GetMapping("/loginUser")
public String getUserLoginPage() {
    if (isAuthenticated()) {
        return "redirect:userMainPage";
    }
    return "loginUser";
}

4. Using an Interceptor

4.使用拦截器

Another way to redirect users is through an interceptor on the URI of the login page.

另一种重定向用户的方法是在登录页面的URI上设置拦截器。

The interceptor will intercept the request before it arrives at the controller. Therefore, we can decide based on the authentication if we let it go further or we block it and return a redirect response.

拦截器将在请求到达控制器之前拦截它。因此,我们可以根据认证来决定是让它继续下去,还是阻止它并返回一个重定向响应。

If the user is authenticated, we’ll need to modify two things in the response:

如果用户通过了认证,我们就需要在响应中修改两件事。

  • Set the status code to HttpStatus.SC_TEMPORARY_REDIRECT
  • Add the Location header with the redirect URL

And finally, we’ll interrupt the execution chain by returning false:

最后,我们将通过返回false来中断执行链。

public class LoginPageInterceptor implements HandlerInterceptor {
    UrlPathHelper urlPathHelper = new UrlPathHelper();
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if ("/loginUser".equals(urlPathHelper.getLookupPathForRequest(request)) && isAuthenticated()) {
            String encodedRedirectURL = response.encodeRedirectURL(
              request.getContextPath() + "/userMainPage");
            response.setStatus(HttpStatus.SC_TEMPORARY_REDIRECT);
            response.setHeader("Location", encodedRedirectURL);

            return false;
        } else {
            return true;
        }
    }

    // isAuthenticated method 
}

We’ll also need to add the interceptor to the Spring MVC lifecycle:

我们还需要将拦截器添加到Spring MVC的生命周期中

@Configuration
public class LoginRedirectMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginPageInterceptor());
    }
}

We could use Spring’s XML Schema-based configuration to achieve the same:

我们可以使用Spring的基于XML Schema的配置来实现。

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/loginUser"/>
        <bean class="com.baeldung.loginredirect.LoginPageInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

5. Using a Filter

5.使用过滤器

Similarly, we can implement a Spring filter.

类似地,我们可以实现一个Spring过滤器。

The filter can be directly applied to the SecurityContext using Spring Security’s filter chain. Thus, it can intercept the request right after the authentication is created.

该过滤器可以使用Spring Security的过滤器链直接应用于SecurityContext。因此,它可以在认证创建后立即拦截请求。

Let’s extend the GenericFilterBean, override the doFilter method, and verify the authentication:

让我们扩展GenericFilterBean,重写doFilter方法,并验证认证。

public class LoginPageFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
        HttpServletRequest servletRequest = (HttpServletRequest) request;
        HttpServletResponse servletResponse = (HttpServletResponse) response;

        if (isAuthenticated() && "/loginUser".equals(servletRequest.getRequestURI())) {

            String encodedRedirectURL = ((HttpServletResponse) response).encodeRedirectURL(
              servletRequest.getContextPath() + "/userMainPage");

            servletResponse.setStatus(HttpStatus.SC_TEMPORARY_REDIRECT);
            servletResponse.setHeader("Location", encodedRedirectURL);
        }

        chain.doFilter(servletRequest, servletResponse);
    }
    // isAuthenticated method 
}

We’ll need to add the filter after the UsernamePasswordAuthenticationFilter in the filter chain.

我们需要在过滤器链中的UsernamePasswordAuthenticationFilter 之后添加该过滤器。

Moreover, we will need to authorize the request for the login page URI to enable the filter chain for it:

此外,我们将需要授权登录页面URI的请求,以启用它的过滤链。

@Configuration
@EnableWebSecurity
public class LoginRedirectSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
          .addFilterAfter(new LoginPageFilter(), UsernamePasswordAuthenticationFilter.class)
          .authorizeRequests().antMatchers("/loginUser").permitAll()
           
        // Other security configuration
    }
}

Finally, if we choose to use XML configuration, we can define the bean for the filter, and add it to the filter chain in the security HTTP tag:

最后,如果我们选择使用XML配置,我们可以为过滤器定义Bean,并将其添加到安全HTTP标签的过滤器链中。

<beans:bean id="loginPageFilter" class="com.baeldung.loginredirect.LoginPageFilter"/>

<security:http pattern="/**" use-expressions="true" auto-config="true">
    <security:intercept-url pattern="/loginUser" access="permitAll"/>
    <security:custom-filter after="BASIC_AUTH_FILTER" ref="loginPageFilter"/>
</security:http>

A quick tutorial on how to create a custom filter for Spring Security can be found here.

关于如何为Spring Security创建自定义过滤器的快速教程可在此处找到。

6. Conclusion

6.结语

In this tutorial, we’ve explored multiple ways how to redirect already logged in users from the login page using Spring Security.

在本教程中,我们已经探索了多种方法,如何使用Spring Security从登录页面重定向已经登录的用户。

As always, the complete source code used in this tutorial is available over on GitHub.

一如既往,本教程中使用的完整源代码可在GitHub上获得

Another tutorial that might be of interest is Redirect to Different Pages after Login with Spring Security, in which we learn how to redirect different types of users to specific pages.

另一个可能感兴趣的教程是Redirect to Different Pages after Login with Spring Security,其中我们学习了如何将不同类型的用户重定向到特定页面。