认证失败或者是授权失败的情况下也能和我们的接口一样返回相同结构的json

这样可以让前端能对响应进行统一的处理。要实现这个功能我们需要知道SpringSecurity的异常处理机制。

例如:当我们登录时

如果登录失败,返回的JSON如下

1
2
3
4
5
6
7
{
"timestamp": "2022-08-21T14:00:09.643+00:00",
"status": 403,
"error": "Forbidden",
"message": "",
"path": "/user/login"
}

如果登录成功,返回的JSON如下

1
2
3
4
5
6
7
{
"code": 200,
"msg": "登陆成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIzYjg0MDEzZTk4MjA0OWViYmQwMTUxZTVlYTViMjllYSIsInN1YiI6IjMiLCJpc3MiOiJzZyIsImlhdCI6MTY2MTA5MDUzNCwiZXhwIjoxNjYxMDk0MTM0fQ.4gxXmtTBqpIE7TpuTGnpCxlkSOw7ikOagzLypc2pQPU"
}
}

为了统一JSON的格式

image-20211214144425527

SpringSecurity中,如果我们在认证或者授权的过程中出现了异常会被ExceptionTranslationFilter捕获到。在ExceptionTranslationFilter中会去判断是认证失败还是授权失败出现的异常。

注意:在认证授权的过程中发生的任何异常都会被抛出,也就是说在控制台是看不见的。当程序在认证授权过程中出问题时,需要DEBUG去查看,然后try...catch捕获异常,看看是什么原因报错。

  • 如果是认证过程中出现的异常会被封装成AuthenticationException然后调用AuthenticationEntryPoint对象的方法去进行异常处理。

  • 如果是授权过程中出现的异常会被封装成AccessDeniedException然后调用AccessDeniedHandler对象的方法去进行异常处理。

自定义异常处理

如果我们需要自定义异常处理,我们只需要自定义AuthenticationEntryPointAccessDeniedHandler然后配置给SpringSecurity即可。

  1. 创建一个包 handler

  2. 自定义实现类

    1. 实现AuthenticationEntryPoint接口【处理认证过程中】

      1. 首先需要定义一个响应对象,new ResponseResult(403, "权限不足");

        认证失败响应码可以是401,或者是HttpStatus.UNAUTHORIZED.value()

      2. 将对象序列化为JSON字符串JSON.toJSONString()

      3. 使用WebUtils工具类,将字符串写到response

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      @Component
      public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
      @Override
      public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {

      ResponseResult result = new ResponseResult(401, "认证失败请重新登录");
      String json = JSON.toJSONString(result);
      WebUtils.renderString(response,json);
      }
      }

    2. 实现AccessDeniedHandler接口【处理授权过程中】

      过程和上面一样

      权限不足响应码可以是403,或者是HttpStatus.FORBIDDEN.value()

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      @Component
      public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
      @Override
      public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {

      ResponseResult result = new ResponseResult(403, "权限不足");
      String jsonString = JSON.toJSONString(result);
      WebUtils.renderString(httpServletResponse,jsonString);
      }
      }
  3. 配置SpringSecurity工具类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    @Configuration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter{
    @Autowired
    private AccessDeniedHandler accessDeniedHandler;

    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Bean
    public PasswordEncoder passwordEncoder(){
    return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {


    //配置异常处理器。
    http.exceptionHandling()
    .authenticationEntryPoint(authenticationEntryPoint)
    .accessDeniedHandler(accessDeniedHandler);
    }
    }

WebUtils工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class WebUtils
{
/**
* 将字符串渲染到客户端
*
* @param response 渲染对象
* @param string 待渲染的字符串
* @return null
*/
public static String renderString(HttpServletResponse response, String string) {
try
{
response.setStatus(200);
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
response.getWriter().print(string);
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
}

还拿之前的举例

例如:当我们登录时

如果登录失败,返回的JSON如下

1
2
3
4
{
"code": 403,
"msg": "认证失败请重新登录"
}

如果登录成功,返回的JSON如下

1
2
3
4
5
6
7
{
"code": 200,
"msg": "登陆成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIzYjg0MDEzZTk4MjA0OWViYmQwMTUxZTVlYTViMjllYSIsInN1YiI6IjMiLCJpc3MiOiJzZyIsImlhdCI6MTY2MTA5MDUzNCwiZXhwIjoxNjYxMDk0MTM0fQ.4gxXmtTBqpIE7TpuTGnpCxlkSOw7ikOagzLypc2pQPU"
}
}

__END__