如何包装OAuth2exception?

我们有一个使用Spring OAuth2的rest API。 用户通过身份validation后,所有JSON响应都采用以下格式:

 {"code" : 12345, "data" : "..." } 

但是,身份validation失败的JSON响应与上述格式不一致,因为它由Spring处理。

例如,如果凭据不正确,客户端将获得带有JSON响应的HTTP状态代码400,如下所示:

 {"error": "invalid_grant", "error_description": "Bad credentials" } 

如果用户帐户被锁定,客户端将获得具有JSON响应的HTTP状态代码400,如下所示

 {"error":"invalid_grant","error_description":"User account is locked"} 

所有这一切都是因为Spring TokenEndpoint.handleException()正在处理与/ oauth / token相关的exception

我想更改OAuth2失败的JSON响应以遵循第一种格式。

这是我迄今为止尝试过的,没有成功:

  1. 使用具有最高优先级顺序的ControllerAdvice并使用此处所述的@ExceptionHandler
  2. 如此处所述实现OAuth2ExceptionRenderer
  3. 实现ExceptionMapper
  4. 添加了一个新的ObjectMapper,扩展了StdSerializer。 虽然我的objectmapper已初始化,但它不用于序列化exception。 也许是因为Spring直接调用MappingJackson2HttpMessageConverter而且我的应用程序中似乎有这个类的几个实例。

任何上述方法或新方法的任何帮助将受到高度赞赏。

我没有尝试过这种方法,因为我无法更改现有客户端的上下文路径。

我面临完全相同的问题并最终解决问题。 我使用一个自定义的ExceptionHandlerExceptionResolver类作为解析器,它在下面的代码中显示了覆盖方法getExceptionHandler ,然后再次使用具有最高优先级顺序的@ControllerAdvice,最后它可以工作。

 public class MyExceptionHandlerExceptionResolver extends ExceptionHandlerExceptionResolver { private Map exceptionHandlerAdviceCache = null; @Override protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) { Class handlerType = (handlerMethod != null ? handlerMethod.getBeanType() : null); List adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); if (exceptionHandlerAdviceCache==null){ exceptionHandlerAdviceCache = new LinkedHashMap(); for (ControllerAdviceBean adviceBean:adviceBeans){ ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(adviceBean.getBeanType()); exceptionHandlerAdviceCache.put(adviceBean, resolver); } } for (Map.Entry entry : this.exceptionHandlerAdviceCache.entrySet()) { if (entry.getKey().isApplicableToBeanType(handlerType)) { ExceptionHandlerMethodResolver resolver = entry.getValue(); Method method = resolver.resolveMethod(exception); if (method != null) { return new ServletInvocableHandlerMethod(entry.getKey().resolveBean(), method); } } } return null; } } 

在configure中使用MyExceptionHandlerExceptionResolver类

 @EnableWebMvc @Configuration public class WebMVCConfiguration extends WebMvcConfigurationSupport { @Bean public ExceptionHandlerExceptionResolver handlerExceptionResolver() { MyExceptionHandlerExceptionResolver exceptionResolver = new MyExceptionHandlerExceptionResolver(); exceptionResolver.setOrder(0); exceptionResolver.setMessageConverters(messageConverters()); return exceptionResolver; } private MappingJackson2HttpMessageConverter jsonHttpMessageConverter() { return new MappingJackson2HttpMessageConverter(); } private List> messageConverters() { List> messageConverters = new ArrayList<>(); messageConverters.add(jsonHttpMessageConverter()); return messageConverters; } } 

如果要处理身份validation过程,可以设置自己的自定义身份validation管理器

             

创建实现AuthenticationProvider自定义身份validation提供程序

 public class UserAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication; String username = auth.getName(); String password = token.getCredentials().toString(); User user = userService.loadByUsername(username); if(user.isLocked){ throw new UserLockedException("User is locked"); } if(another.something.bad.happened){ throw new AnotherSomethingBadHappenedException("Error"); } // setup authorities //... return new UsernamePasswordAuthenticationToken(user, password, authorities); } } 

现在您有了自己的exception,并且通过使用ExceptionMapper,您可以将身份validation过程中抛出的exception转换为自定义响应消息。

您可以创建的另一个自定义是通过创建扩展ApprovalStoreUserApprovalHandler的自定义类来实现授权过程

 public class CustomUserApprovalHandler extends ApprovalStoreUserApprovalHandler { // stripped @Override public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest, Authentication userAuthentication) { ClientDetails client = clientDetailsService .loadClientByClientId(authorizationRequest.getClientId()); // here, you have the client and the user // you can do any checking here and throw any exception authorizationRequest.setApproved(approved); return authorizationRequest; } } 

为该类创建bean定义