首页 > 解决方案 > 为错误 Forbidden 实现自定义异常处理程序

问题描述

我想创建自定义异常处理程序,它返回带有数据的结构化 JSON 响应。我试过这个:

@ExceptionHandler({ AccessDeniedException.class })
public ResponseEntity<ErrorResponseDTO> accessDeniedExceptionHandler(final AccessDeniedException ex) {
    ErrorDetail errorDetail = ErrorDetail.NOT_FOUND;

    LOG.error(ex.getMessage(), ex.getCause());
    ErrorResponse errorEntry = new ErrorResponse();
    .......

    return new ResponseEntity<ErrorResponseDTO>(errorResponse, HttpStatus.FORBIDDEN);
}

完整代码:Github

但我得到了这个通用结果:

{
  "timestamp": "2020-06-06T22:46:13.815+00:00",
  "status": 403,
  "error": "Forbidden",
  "message": "",
  "path": "/engine/users/request"
}

我只想得到这个结果:

{
  "errors": [{
    "status": 404,
    "code": "1000",
    "title": "Forbidden",
    "detail": "Forbidden",
    "extra": {
      "detail": "Forbidden"
    }
  }]
}

您知道如何发送自定义结果以及如何解决此问题吗?

标签: javaspringspring-boot

解决方案


好吧,我认为您可以通过这种方式为拒绝访问异常执行自定义错误

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final ObjectMapper om;

    public SecurityConfiguration() {
        this.om = new ObjectMapper();
        this.om.setDefaultPropertyInclusion(JsonInclude.Include.NON_NULL);
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http
            .exceptionHandling()
            .accessDeniedHandler((request, response, accessDeniedException) -> {
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                ServletOutputStream out = response.getOutputStream();
                om.writeValue(
                    out,
                    ErrorDto
                    .builder()
                        .code(1000)
                        .title("Forbidden")
                        .detail("Forbidden")
                        .status(404)
                    .build()
                );
                out.flush();
            }).and()
            .authorizeRequests().antMatchers("/api/**").authenticated()
            .and()
            .httpBasic()
            .and()
            .formLogin().disable();
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    private static class ErrorDto{
        private int status;
        private int code;
        private String title;
        private String detail;
        // other fields
    }
}


推荐阅读