如何包装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响应以遵循第一种格式。
这是我迄今为止尝试过的,没有成功:
- 使用具有最高优先级顺序的ControllerAdvice并使用此处所述的@ExceptionHandler
- 如此处所述实现OAuth2ExceptionRenderer
- 实现ExceptionMapper
- 添加了一个新的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定义