我们有一个使用Spring OAuth2
的其他API。用户通过身份验证后,所有JSON响应都采用以下格式:
{"code" : 12345, "data" : "..." }
但是,身份验证失败的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相关的异常
我想将OAuth2失败的JSON响应更改为遵循第一种格式。
这是我迄今为止尝试过的,但没有成功:
任何上述方法或新方法的任何帮助都将受到高度赞赏。
我没有尝试this方法,因为我无法更改现有客户端的上下文路径。
答案 0 :(得分:1)
我遇到了完全相同的问题并最终解决了问题。 我使用一个自定义的ExceptionHandlerExceptionResolver类作为解析器,它覆盖了下面代码中显示的方法 getExceptionHandler ,然后再次使用具有最高优先级顺序的@ControllerAdvice,最后它可以工作。
public class MyExceptionHandlerExceptionResolver extends ExceptionHandlerExceptionResolver {
private Map<ControllerAdviceBean, ExceptionHandlerMethodResolver> exceptionHandlerAdviceCache = null;
@Override
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
Class<?> handlerType = (handlerMethod != null ? handlerMethod.getBeanType() : null);
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
if (exceptionHandlerAdviceCache==null){
exceptionHandlerAdviceCache = new LinkedHashMap<ControllerAdviceBean, ExceptionHandlerMethodResolver>();
for (ControllerAdviceBean adviceBean:adviceBeans){
ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(adviceBean.getBeanType());
exceptionHandlerAdviceCache.put(adviceBean, resolver);
}
}
for (Map.Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> 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<HttpMessageConverter<?>> messageConverters() {
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(jsonHttpMessageConverter());
return messageConverters;
}
}
答案 1 :(得分:0)
如果要处理身份验证过程,可以设置自己的自定义身份验证管理器
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password authentication-manager-ref="customAuthenticationManager" />
</oauth:authorization-server>
<authentication-manager id="customAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>
<bean id="customAuthenticationProvider"
class="com.any.CustomAuthenticationProvider">
</bean>
创建实现AuthenticationProvider
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);
}
}
现在您有了自己的异常,并且通过使用ExceptionMapper,您可以将身份验证过程中抛出的异常转换为自定义响应消息。
您可以通过创建扩展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定义
<bean id="userApprovalHandler"
class="com.any.CustomUserApprovalHandler">
<property name="approvalStore" ref="approvalStore" />
<property name="requestFactory" ref="oAuth2RequestFactory" />
<property name="clientDetailsService" ref="clientDetails" />
<property name="useApprovalStore" value="true" />
</bean>