Handle Spring Security Exceptions – 处理Spring安全异常

最后修改: 2022年 4月 26日

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

1. Overview

1.概述

In this article, we’ll have a look at how to handle Spring Security exceptions produced by our Spring Security Resource Server. To do so, we’ll also use a practical example where all the necessary configurations will be explained. First of all, let’s make a short introduction to Spring Security.

在这篇文章中,我们将看看如何处理由我们的Spring Security Resource Server产生的Spring Security异常。为此,我们还将使用一个实际的例子,所有必要的配置都将被解释。首先,让我们对Spring Security做一个简短的介绍。

2. Spring Security

2.Spring安全

Spring Security is a library that’s part of the Spring project. It tries to group all the functionalities of user access control on Spring projects. Access control allows limiting the options that can be executed by a given set of users or roles on the application. In this direction, Spring Security controls invocations to business logic or limits the access of HTTP requests to certain URLs. With this in mind, we must configure the application by telling Spring Security how the security layer should behave.

Spring Security是一个库,是Spring项目的一部分。它试图将用户访问控制的所有功能集中在Spring项目上。访问控制允许限制一组特定的用户或角色在应用程序上可以执行的选项。在这个方向上,Spring Security控制对业务逻辑的调用或限制HTTP请求对某些URL的访问。考虑到这一点,我们必须通过告诉Spring Security安全层应该如何行事来配置应用程序。

In our case, we’ll focus on the configuration of exception handlers. Spring Security offers three different interfaces to accomplish this purpose and to control the events produced:

在我们的案例中,我们将专注于异常处理程序的配置。Spring Security提供了三种不同的接口来完成这一目的,并控制产生的事件:

  • Authentication Success Handler
  • Authentication Failure Handler
  • Access Denied Handler

Firstly, let’s take a closer look at the configuration.

首先,让我们仔细看一下配置。

3. Security Configuration

3.安全配置

First of all, we’ve our configuration class that has to create a SecurityFilterChain bean. This will be in charge of managing all the security configurations of the application. So, it’s here where we have to introduce our handlers.

首先,我们的配置类必须创建一个SecurityFilterChainbean。这将负责管理应用程序的所有安全配置。因此,我们必须在这里介绍我们的处理程序。

On the one hand, we’ll define the required configuration:

一方面,我们将定义所需的配置。

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.csrf()
        .disable()
        .httpBasic()
        .disable()
        .authorizeRequests()
        .antMatchers("/login")
        .permitAll()
        .antMatchers("/customError")
        .permitAll()
        .antMatchers("/access-denied")
        .permitAll()
        .antMatchers("/secured")
        .hasRole("ADMIN")
        .anyRequest()
        .authenticated()
        .and()
        .formLogin()
        .failureHandler(authenticationFailureHandler())
        .successHandler(authenticationSuccessHandler())
        .and()
        .exceptionHandling()
        .accessDeniedHandler(accessDeniedHandler())
        .and()
        .logout();
    return http.build();
}

It’s interesting to note that redirection URLs, such as “/login”, “/customError”, and “/access-denied” don’t have to have any type of restriction to access them. So, we annotate them as permitAll().

值得注意的是,重定向URL,如“/login”“/customError”“/access-denied”,不需要有任何类型的限制来访问它们。所以,我们把它们注释为permitAll()

On the other hand, we’ve to define the Beans that define the types of exceptions that we can handle:

另一方面,我们必须定义Bean,定义我们可以处理的异常类型。

@Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
    return new CustomAuthenticationFailureHandler();
} 

@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() {
   return new CustomAuthenticationSuccessHandler();
}

@Bean
public AccessDeniedHandler accessDeniedHandler() {
   return new CustomAccessDeniedHandler();
}

Since the AuthenticationSuccessHandler handles the happy path, we’ll define the two remaining beans for the exception cases. These two handlers are the ones we now have to adapt and implement to our needs. So, let’s proceed with the implementation of each of them.

由于AuthenticationSuccessHandler处理快乐的路径,我们将为异常情况定义剩下的两个bean。这两个处理程序 是我们现在必须根据我们的需要来调整和实现的。所以,让我们继续实现它们中的每一个。

4. Authentication Failure Handler

4.认证失败处理程序

On the one hand, we’ve got the AuthenticationFailureHandler interface. That’s in charge of managing the exceptions produced when the user fails to log in. This interface provides us with the onAuthenticationFailure() method to customize the handler logic. It will be invoked by Spring Security upon a failed login attempt. With this in mind, let’s define our exception handler to redirect us to the error page when a failed login occurs:

一方面,我们有AuthenticationFailureHandler接口。它负责管理用户登录失败时产生的异常。这个接口为我们提供了onAuthenticationFailure()方法来定制处理程序逻辑。当登录尝试失败时,Spring Security将调用该方法。考虑到这一点,让我们定义我们的异常处理程序,当登录失败时将我们重定向到错误页面。

public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) 
      throws IOException {
        response.sendRedirect("/customError");
    }
}

5. Access Denied Handler

5.拒绝访问的处理程序

On the other hand, when an unauthorized user tries to access the secure or protected page, Spring Security will throw an access denied exception. There’s a default 403 access denied page available with Spring Security which we can customize. This is managed by the AccessDeniedHandler interface. In addition, it provides the handle() method for custom the logic before redirecting the user to the 403 page:

另一方面,当未经授权的用户试图访问安全或受保护的页面时,Spring Security会抛出一个拒绝访问的异常。Spring Security提供了一个默认的403访问拒绝页面,我们可以自定义。这是由AccessDeniedHandler接口管理的。此外,它还提供了handle()方法,用于在将用户重定向到403页面之前自定义逻辑

public class CustomAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exc) throws IOException {
        response.sendRedirect("/access-denied");
    }
}

6. Conclusion

6.结语

In this quick article, we’ve learned how to handle Spring Security exceptions and how to control them by creating and customizing our classes. In addition, we’ve created a fully functional example that helps us with understanding the concepts explained.

在这篇简短的文章中,我们学习了如何处理Spring Security异常,以及如何通过创建和定制我们的类来控制它们。此外,我们还创建了一个功能齐全的例子,帮助我们理解所解释的概念。

The complete source code of the article is available over on GitHub.

文章的完整源代码可在GitHub上获得over。