在实际的工作中,我们经常会涉及到统一返回的异常信息,例如:
{
"errorCode": 200,
"errorMsg": "请求成功",
"data": null
}这种统一形式的异常信息,但是在这里我们的spring security oauth里面返回的错误信息格式不一样,示例如下:
这里的错误信息格式是这样子的:
{
"error": "unauthorized",
"error_description": "没有此应用客户端"
}此时就会产生困扰,前端同学是不是要写多套json解析来处理不同的返回值呢? 有没有什么办法可以把oauth这边的返回给转换成和正常业务保持一致的样式呢?答案是有的,就是我们这里自定义这个endpoint的配置即可。
首先我们创建一个CustomClientCredentialsTokenEndpointFilter类,这个类继承制ClientCredentialsTokenEndpointFilter类,这里主要的实现逻辑就是设置成功或者失败的处理handler,完整代码示例如下:
package org.shop.oauth.server.handler;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter;
import org.springframework.security.web.AuthenticationEntryPoint;
public class CustomClientCredentialsTokenEndpointFilter extends ClientCredentialsTokenEndpointFilter {
private final AuthorizationServerSecurityConfigurer configurer;
private AuthenticationEntryPoint authenticationEntryPoint;
public CustomClientCredentialsTokenEndpointFilter(AuthorizationServerSecurityConfigurer configurer) {
this.configurer = configurer;
}
@Override
public void setAuthenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
this.authenticationEntryPoint = authenticationEntryPoint;
}
@Override
protected AuthenticationManager getAuthenticationManager() {
return configurer.and().getSharedObject(AuthenticationManager.class);
}
@Override
public void afterPropertiesSet() {
setAuthenticationFailureHandler((request, response, exception) -> authenticationEntryPoint.commence(request, response, exception));
setAuthenticationSuccessHandler((request, response, authentication) -> {
});
}
}接着我们需要编写一个自定义的endpoint来处理返回内容,完整代码示例如下:
package org.shop.oauth.server.entrypoint; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.shop.common.model.http.BaseResponse; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSON; @Component("customAuthenticationEntryPoint") public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { response.setStatus(200); BaseResponse fail = BaseResponse.fail(authException.getMessage()); response.setHeader("Content-Type", "application/json;charset=utf-8"); response.getWriter().print(JSON.toJSONString(fail)); response.getWriter().flush(); } }
自定义的类我们编写好了,接下来就是配置即可,这里配置的话,我们还是在oauthconfig里面改,修改的方法是:
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {}完整的代码逻辑如下:
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
CustomClientCredentialsTokenEndpointFilter endpointFilter = new CustomClientCredentialsTokenEndpointFilter(security);
endpointFilter.afterPropertiesSet();
endpointFilter.setAuthenticationEntryPoint(customAuthenticationEntryPoint);
// 客户端认证之前的过滤器
security.addTokenEndpointAuthenticationFilter(endpointFilter);
}然后我们启动下项目,看看效果:
可以看到异常的返回值被改写了。
备注:
1、这里我们在配置oauthconfig的时候,主要是添加如下的代码:
CustomClientCredentialsTokenEndpointFilter endpointFilter = new CustomClientCredentialsTokenEndpointFilter(security); endpointFilter.afterPropertiesSet(); endpointFilter.setAuthenticationEntryPoint(customAuthenticationEntryPoint); // 客户端认证之前的过滤器 security.addTokenEndpointAuthenticationFilter(endpointFilter);
但是在前面的演示里面我们添加的代码是:
security.allowFormAuthenticationForClients() .authenticationEntryPoint(new OAuth2AuthenticationEntryPoint());
为了自定义返回结果,这里的话,我们需要把allowFormAuthenticationForClients这一坨给去掉,只保留:
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
CustomClientCredentialsTokenEndpointFilter endpointFilter = new CustomClientCredentialsTokenEndpointFilter(security);
endpointFilter.afterPropertiesSet();
endpointFilter.setAuthenticationEntryPoint(customAuthenticationEntryPoint);
// 客户端认证之前的过滤器
security.addTokenEndpointAuthenticationFilter(endpointFilter);
}最后按照惯例,附上本案例的源码,登录后即可下载



还没有评论,来说两句吧...