30t*_*thh 9 spring json spring-mvc spring-security spring-boot
我正在开发一个REST服务.它使用JSON,并且在出现问题时必须返回一些预定义的JSON对象.默认的Spring响应如下所示:
{
"timestamp": 1512578593776,
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/swagger-ui.html"
}
Run Code Online (Sandbox Code Playgroud)
我想用自己的JSON替换这个默认的JSON(带有栈跟踪和其他异常相关信息).
Spring提供了一种覆盖默认行为的便捷方法.应该定义一个@RestControllerAdvice带有自定义异常处理程序的bean.像这样
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = {Exception.class})
public ResponseEntity<ExceptionResponse> unknownException(Exception ex) {
ExceptionResponse resp = new ExceptionResponse(ex, level); // my custom response object
return new ResponseEntity<ExceptionResponse>(resp, resp.getStatus());
}
@ExceptionHandler(value = {AuthenticationException.class})
public ResponseEntity<ExceptionResponse> authenticationException(AuthenticationExceptionex) {
// WON'T WORK
}
}
Run Code Online (Sandbox Code Playgroud)
ExceptionResponse然后,Spring将使用特殊的消息转换器将自定义对象转换为JSON.
问题是,安全例外InsufficientAuthenticationException不能被注释为的方法拦截@ExceptionHandler.这种异常发生在输入Spring MVC调度程序servlet并初始化所有MVC处理程序之前.
可以使用自定义筛选器拦截此异常,并从头开始构建自己的JSON序列化.在这种情况下,可以获得一个完全独立于Spring MVC基础结构的其余部分的代码.这不好.
我找到的解决方案似乎有效,但看起来很疯狂.
@Configuration
public class CustomSecurityConfiguration extends
WebSecurityConfigurerAdapter {
@Autowired
protected RequestMappingHandlerAdapter requestMappingHandlerAdapter;
@Autowired
protected GlobalExceptionHandler exceptionHandler;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.fullyAuthenticated();
http.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint());
}
public AuthenticationEntryPoint authenticationEntryPoint() {
return new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
try {
ResponseEntity<ExceptionResponse> objResponse = exceptionHandler.authenticationException(authException);
Method unknownException = exceptionHandler.getClass().getMethod("authenticationException", AuthenticationException.class);
HandlerMethod handlerMethod = new HandlerMethod(exceptionHandler, unknownException);
MethodParameter returnType = handlerMethod.getReturnValueType(objResponse);
ModelAndViewContainer mvc = new ModelAndViewContainer(); // not really used here.
List<HttpMessageConverter<?>> mconverters = requestMappingHandlerAdapter.getMessageConverters();
DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request, response);
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(mconverters);
processor.handleReturnValue(objResponse, returnType, mvc, webRequest);
} catch (IOException e) {
throw e;
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new ServletException(e);
}
}
};
}
Run Code Online (Sandbox Code Playgroud)
有没有办法使用Spring序列化管道(在消息转换器中使用Spring构建,MIME格式协商等)看起来比这更好?
创建Bean类
@Component public class AuthenticationExceptionHandler implements AuthenticationEntryPoint, Serializable
Run Code Online (Sandbox Code Playgroud)
并commence() method使用对象映射器覆盖并创建 json 响应,如下例所示
ObjectMapper mapper = new ObjectMapper();
String responseMsg = mapper.writeValueAsString(responseObject);
response.getWriter().write(responseMsg);
Run Code Online (Sandbox Code Playgroud)
并@Autowire AuthenticationExceptionHandler在SecurityConfiguration课堂上configure(HttpSecurity http) method添加以下行
http.exceptionHandling()
.authenticationEntryPoint(authenticationExceptionHandler)
Run Code Online (Sandbox Code Playgroud)
这样,您应该能够发送自定义 json 响应 401 /403。与上面相同,您可以使用AccessDeniedHandler. 请告诉我们这是否帮助您解决了问题。
Spring 通过 提供了对异常处理的开箱即用支持,可以通过以下步骤来利用它来在ieAccessDeniedHandler的情况下实现自定义 JSON 响应AccessDeniedExceptionHTTP 403
实现一个自定义处理程序,如下所示
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exc)
throws IOException, ServletException {
System.out.println("Access denied .. ");
// do something
response.sendRedirect("/deny");
}
}
Run Code Online (Sandbox Code Playgroud)
接下来在配置中创建此处理程序的一个bean,并将其提供给 spring security 异常处理程序(重要提示-确保从身份验证中排除/deny,否则请求将无限地继续解决错误)
@Bean
public AccessDeniedHandler accessDeniedHandler(){
return new CustomAccessDeniedHandler();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
// some other configuration
.antMatchers("/deny").permitAll()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler());
}
Run Code Online (Sandbox Code Playgroud)
接下来,在控制器类中编写一个对应的处理程序/deny,并简单地抛出一个新实例SomeException(或任何其他Exception合适的实例),该实例将在相应的处理程序中被拦截@RestControllerAdvice。
@GetMapping("/deny")
public void accessDenied(){
throw new SomeException("User is not authorized");
}
Run Code Online (Sandbox Code Playgroud)
如果需要更多信息,请在评论中告知。
| 归档时间: |
|
| 查看次数: |
3879 次 |
| 最近记录: |