Spring Security combat dry goods: custom exception handling

Keywords: Programming Spring Java JSON

1. Preface

It's really busy these days. It's hard to find time to continue to improve Spring Security practical dry goods series . Today, Spring Security needs to handle the authentication and authorization exceptions in the project, so share it.

2. Exceptions in spring security

There are two main types of exceptions in Spring Security: one is authentication exception, the other is authorization related exception.

2.1 AuthenticationException

AuthenticationException is an exception thrown when an error occurs during user authentication. The main subclasses are shown in the figure:

According to the information in the figure, the system user does not exist, is locked, the credential is invalid, the password is wrong and other exceptions in the authentication process are handled by the AuthenticationException.

2.2 AccessDeniedException

AccessDeniedException is an exception thrown when a user is denied access to a protected resource. Like AuthenticationException, it also provides some concrete subclasses. The following picture:

There are few subclasses of AccessDeniedException, mainly CSRF related exceptions and authorization service exceptions.

3. Regulations of HTTP status on authentication and authorization

Http protocol also provides for the response results of authentication and authorization.

3.1 401 unauthorized status

HTTP 401 error - unauthorized this error message generally indicates that you need to log in first (enter a valid user name and password) If you just input these information, you will immediately see a 401 error, which means that your user name and password are invalid for any reason (incorrect input, user name is temporarily disabled, account is locked, voucher is invalid, etc.). All in all, authentication failed. Actually, it corresponds to the AuthenticationException above.

3.2 403 rejected status

HTTP 403 error - Forbidden this error indicates that you are not authorized to access restricted resources. The server understands the request but refuses to perform the task. The request should not be sent back to the server. And if the server wants the client to know why they do not have permission to access a specific resource, the server should describe the reason for the denial in the returned information. In general practice, we will show the reasons vaguely This error corresponds to the AccessDeniedException above.

4. Exception handling in spring security

In our Spring Security practical dry goods series Custom configuration class entry WebSecurityConfigurerAdapter The exception handling () method provided by HttpSecurity is mentioned in the article to provide exception handling. This method constructs the ExceptionHandlingConfigurer exception handling configuration class. This configuration class provides two practical interfaces:

  • AuthenticationEntryPoint this class is used to uniformly handle AuthenticationException exceptions
  • AccessDeniedHandler this class is used to uniformly handle AccessDeniedException exceptions

As long as we implement and configure these two exception handling classes, we can implement unified custom handling of exceptions related to Spring Security authentication and authorization.

4.1 implementation of AuthenticationEntryPoint

Respond with json information.

 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.springframework.http.MediaType;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.web.AuthenticationEntryPoint;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashMap;
 
 /**
  * @author dax
  * @since 2019/11/6 22:11
  */
 public class SimpleAuthenticationEntryPoint implements AuthenticationEntryPoint {
     @Override
     public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
 
         //todo your business
         HashMap<String, String> map = new HashMap<>(2);
         map.put("uri", request.getRequestURI());
         map.put("msg", "Authentication failed");
         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
         response.setCharacterEncoding("utf-8");
         response.setContentType(MediaType.APPLICATION_JSON_VALUE);
         ObjectMapper objectMapper = new ObjectMapper();
         String resBody = objectMapper.writeValueAsString(map);
         PrintWriter printWriter = response.getWriter();
         printWriter.print(resBody);
         printWriter.flush();
         printWriter.close();
     }
 }

4.2 implementation of AccessDeniedHandler

Also respond with json information.

 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.springframework.http.MediaType;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.web.access.AccessDeniedHandler;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashMap;
 
 /**
  * @author dax
  * @since 2019/11/6 22:19
  */
 public class SimpleAccessDeniedHandler implements AccessDeniedHandler {
     @Override
     public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
         //todo your business
         HashMap<String, String> map = new HashMap<>(2);
         map.put("uri", request.getRequestURI());
         map.put("msg", "Authentication failed");
         response.setStatus(HttpServletResponse.SC_FORBIDDEN);
         response.setCharacterEncoding("utf-8");
         response.setContentType(MediaType.APPLICATION_JSON_VALUE);
         ObjectMapper objectMapper = new ObjectMapper();
         String resBody = objectMapper.writeValueAsString(map);
         PrintWriter printWriter = response.getWriter();
         printWriter.print(resBody);
         printWriter.flush();
         printWriter.close();
     }
 }

4.3 personal practice suggestions

In fact, I personally suggest that Http status codes all return 200 and 401 status is returned in the meta information Map. Because the exception status code will be displayed in error on the browser side. As long as we can capture 401 and 403, we can determine whether it is authentication or authorization.

4.4 configuration

After the above two interfaces are implemented, we only need to configure them in the configure(HttpSecurity http) method of websecurity configureradapter. The related configuration fragments are as follows:

 http.exceptionHandling().accessDeniedHandler(new SimpleAccessDeniedHandler()).authenticationEntryPoint(new SimpleAuthenticationEntryPoint())

5. summary

Today we explained exception handling in Spring Security. The user-defined authentication exception handling and user-defined authorization exception handling are implemented respectively. Related DEMO can focus on WeChat public number: Felordcn reply ss07 access.

Pay attention to the public address: Felordcn for more information

Personal blog: https://felord.cn

Posted by varun8211 on Wed, 06 Nov 2019 10:28:13 -0800