在实际的工作中,我们经常会涉及到统一返回的异常信息,例如:
{ "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); }
最后按照惯例,附上本案例的源码,登录后即可下载
还没有评论,来说两句吧...