当前位置: 首页 > 知识库问答 >
问题:

处理Spring Boot Resource Server中的安全异常

狄海
2023-03-14

如何使自定义的ResponseEntityExceptionHandlerOAuth2ExceptionRenderer来处理Spring security在纯资源服务器上引发的异常?

我们实现了一个

@ControllerAdvice
@RestController
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

因此,每当资源服务器上出现错误时,我们希望它以

{
  "message": "...",
  "type": "...",
  "status": 400
}
security.oauth2.resource.userInfoUri: http://localhost:9999/auth/user

根据我们的身份验证服务器对请求进行身份验证和授权。

但是,任何Spring Security错误总是会绕过我们的异常处理程序

    @ExceptionHandler(InvalidTokenException.class)
    public ResponseEntity<Map<String, Object>> handleInvalidTokenException(InvalidTokenException e) {
        return createErrorResponseAndLog(e, 401);
    }

并产生其中之一

{
  "timestamp": "2016-12-14T10:40:34.122Z",
  "status": 403,
  "error": "Forbidden",
  "message": "Access Denied",
  "path": "/api/templates/585004226f793042a094d3a9/schema"
}
{
  "error": "invalid_token",
  "error_description": "5d7e4ab5-4a88-4571-b4a4-042bce0a076b"
}

我们唯一的配置/设置是:

@SpringBootApplication
@Configuration
@ComponentScan(basePackages = {"our.packages"})
@EnableAutoConfiguration
@EnableResourceServer

共有1个答案

卢鸿彩
2023-03-14

正如前面的注释所指出的,请求在到达MVC层之前被安全框架拒绝,因此@controlleradvice在这里不是一个选项。

Spring Security framework中有3个接口可能是这里感兴趣的:

  • org.springframework.security.web.authentication.authenticationsuccesshandler
  • org.springframework.security.web.authentication.authenticationfailurehandler
  • org.springframework.security.web.access.AccessDeniedHandler

您可以创建这些接口中的每个接口的实现,以便自定义针对各种事件发送的响应:成功登录、失败登录、试图以不足的权限访问受保护的资源。

当登录尝试不成功时,以下将返回一个JSON响应:

@Component
public class RestAuthenticationFailureHandler implements AuthenticationFailureHandler
{
  @Override
  public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
      AuthenticationException ex) throws IOException, ServletException
  {
    response.setStatus(HttpStatus.FORBIDDEN.value());
    
    Map<String, Object> data = new HashMap<>();
    data.put("timestamp", new Date());
    data.put("status",HttpStatus.FORBIDDEN.value());
    data.put("message", "Access Denied");
    data.put("path", request.getRequestURL().toString());
    
    OutputStream out = response.getOutputStream();
    com.fasterxml.jackson.databind.ObjectMapper mapper = new ObjectMapper();
    mapper.writeValue(out, data);
    out.flush();
  }
}

您还需要在安全框架中注册您的实现。在Java配置中,如下所示:

@Configuration
@EnableWebSecurity
@ComponentScan("...")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
  @Override
  public void configure(HttpSecurity http) throws Exception
  {
    http
       .addFilterBefore(corsFilter(), ChannelProcessingFilter.class)
       .logout()
       .deleteCookies("JESSIONID")
       .logoutUrl("/api/logout")
       .logoutSuccessHandler(logoutSuccessHandler())
       .and()
       .formLogin()
       .loginPage("/login")
       .loginProcessingUrl("/api/login")
       .failureHandler(authenticationFailureHandler())
       .successHandler(authenticationSuccessHandler())
       .and()
       .csrf()
       .disable()
       .exceptionHandling()
       .authenticationEntryPoint(authenticationEntryPoint())
       .accessDeniedHandler(accessDeniedHandler());
  }

  /**
   * @return Custom {@link AuthenticationFailureHandler} to send suitable response to REST clients in the event of a
   *         failed authentication attempt.
   */
  @Bean
  public AuthenticationFailureHandler authenticationFailureHandler()
  {
    return new RestAuthenticationFailureHandler();
  }

  /**
   * @return Custom {@link AuthenticationSuccessHandler} to send suitable response to REST clients in the event of a
   *         successful authentication attempt.
   */
  @Bean
  public AuthenticationSuccessHandler authenticationSuccessHandler()
  {
    return new RestAuthenticationSuccessHandler();
  }

  /**
   * @return Custom {@link AccessDeniedHandler} to send suitable response to REST clients in the event of an attempt to
   *         access resources to which the user has insufficient privileges.
   */
  @Bean
  public AccessDeniedHandler accessDeniedHandler()
  {
    return new RestAccessDeniedHandler();
  }
}
 类似资料:
  • 有没有办法在泽西进行全局异常处理?与其单个资源具有try/catch块,然后调用一些方法来清理所有要发回客户端的异常,我希望有一种方法可以将其放在实际调用资源的地方。这可能吗?如果是这样,怎么做? 相反,where会向Jersey servlet抛出某种Jersey配置的异常: 有: 其中异常将被抛出到我可以拦截并从那里调用的东西。 这实际上只是为了简化所有Jersey资源,并确保返回给客户机的异

  • 统一错误处理 文档:https://eggjs.org/zh-cn/tutorials/restful.html 自定义一个异常基类 // app / exceptions / http_exceptions.js class HttpExceptions extends Error { constructor(msg='服务器异常', code=1, httpCode=400) {

  • 我想使用MongoDB用NestJs和TypeORM创建一个应用程序。假设我有一个实体,除了ID字段外,还有两个唯一的字段 当我想用已经存在的或创建一个新模块时,我得到了以下异常错误 因此,在catch语句中,我必须处理传入的错误。我要做的是 TypeORM是否公开预制异常?是否有我可以使用的枚举?获取这些TypeORM数据库错误的好方法是什么? 这里似乎列出了一些错误 https://githu

  • Middleware: 全局异常处理 我们在岩浆的实例其实已经注意到了,compose 的连接方式,让我们有能力精确控制异常。 Koa中间件最终行为强依赖注册顺序,比如我们这里要引入的异常处理,必须在业务逻辑中间件前注册,才能捕获后续中间件中未捕获异常,回想一下我们的调度器实现的异常传递流程。 <?php class ExceptionHandler implements Middleware

  • 在做android项目开发时,大家都知道如果程序出错了,会弹出来一个强制退出的弹出框,这个本身没什么问题,但是这个UI实在是太丑了,别说用户接受不了,就连我们自己本身可能都接受不了。虽然我们在发布程序时总会经过仔细的测试,但是难免会碰到预料不到的错误。 今天就来自定义一个程序出错时的处理,类似iphone的闪退。(虽然闪退也是用户不愿意看到的,但是在用户体验上明显比那个原生的弹窗好多了) 废话不多

  • 问题内容: 有没有办法在Jersey中进行全局异常处理?我希望有一种方法可以将其放置在实际调用资源的地方,而不是单个资源具有try / catch块,然后调用某种方法来清理将要发送回客户端的所有异常。这有可能吗?如果是这样,怎么办? 而是在哪里向Jersey Servlet抛出某种Jersey配置的异常: 具有: 异常会被抛出到我可以拦截并从那里调用的东西。 实际上,这仅仅是为了简化Jersey的