本文主要记录如何自定义spring cloud oauth2认证服务器异常
想必用过spring cloud oauth2的都知道它默认的返回格式,在实际开发中不是很友好,通常情况下我们都是需要统一的数据返回格式,这样才可以不被前端大哥们吐槽
废话不过说直接开始正文了
自定义异常处理
- 编辑LwWebResponseExceptionTranslator实现WebResponseExceptionTranslator,根据不同的异常返回不同的状态码
- 将LwWebResponseExceptionTranslator注入认证服务器替换默认DefaultWebResponseExceptionTranslator实现
接下来看看代码,根据不同的项目有不同的实现方式,我这只是做一个简单的记录,只区别了权限异常和认证异常
@Slf4j
public class LwWebResponseExceptionTranslator implements WebResponseExceptionTranslator {
private ThrowableAnalyzer throwableAnalyzer = new ThrowableAnalyzer();
@Override
public ResponseEntity translate(Exception e) throws Exception {
//获取异常栈信息
Throwable[] throwables = this.throwableAnalyzer.determineCauseChain(e);
//获取AuthenticationException异常信息,不存在则返回的是null
Exception ase = (AuthenticationException) this.throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, throwables);
if (ase != null) {
log.error(ase.getMessage());
return ResponseEntity.ok(R.failed(ResultStatus.AUTH_EXCEPTION.getCode(), ResultStatus.AUTH_EXCEPTION.getMsg()));
}
//获取AccessDeniedException异常信息,不存在则返回的是null
ase = (AccessDeniedException) this.throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, throwables);
if (ase != null) {
log.error(ase.getMessage());
return ResponseEntity.ok(R.failed(ResultStatus.ACCESS_DENIED_EXCEPTION.getCode(), ResultStatus.ACCESS_DENIED_EXCEPTION.getMsg()));
}
return ResponseEntity.ok(R.failed(e.getMessage()));
}
}
// 这是响应实体类
@Builder
@ToString
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
@Getter
@Setter
private String code;
@Getter
@Setter
private String msg;
@Getter
@Setter
private T data;
public static <T> R<T> ok() {
return restResult(null, ResultStatus.SUCCESS.getCode(), "");
}
public static <T> R<T> ok(T data) {
return restResult(data, ResultStatus.SUCCESS.getCode(), "");
}
public static <T> R<T> ok(T data, String msg) {
return restResult(data, ResultStatus.SUCCESS.getCode(), msg);
}
public static <T> R<T> failed() {
return restResult(null, ResultStatus.SUCCESS.getCode(), "");
}
public static <T> R<T> failed(String code, String msg) {
return restResult(null, code, msg);
}
public static <T> R<T> failed(String msg) {
return restResult(null, ResultStatus.FAIL.getCode(), msg);
}
public static <T> R<T> failed(T data) {
return restResult(data, ResultStatus.FAIL.getCode(), "");
}
public static <T> R<T> failed(T data, String msg) {
return restResult(data, ResultStatus.FAIL.getCode(), msg);
}
public boolean isOk() { return this.code.equals(ResultStatus.SUCCESS.getCode()); }
private static <T> R<T> restResult(T data, String code, String msg) {
R<T> result = new R<>();
result.setCode(code);
result.setData(data);
result.setMsg(msg);
return result;
}
}
自定义的LwWebResponseExceptionTranslator类就编写好了,在实际开发中,还可以通过自定义异常类继承OAuth2Exception来做到根据不同的异常返回不同的响应码,这样会更好一点
既然自定义的异常处理类已经完成,下面我们就要去将它替换原有的DefaultWebResponseExceptionTranslator
/**
* 令牌访问端点配置
*
* @param endpoints
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.POST, HttpMethod.GET)
.authenticationManager(authenticationManagerBean)
.tokenServices(tokenServices())
.exceptionTranslator(new LwWebResponseExceptionTranslator()) //替换异常处理类
.tokenStore(tokenStore)
.userDetailsService(lwUserDetailsService);
}
效果展示
小知识: 本文响应实体类只有code,msg,data三个字段,但是实际返回多了一个ok字段,主要原因是R对象中我们有一个
public boolean isOk() { return this.code.equals(ResultStatus.SUCCESS.getCode()); }方法,判断当前对象是否成功状态,
我又使用到lombok插件,lombok布尔类型默认会在字段前面加is,比如
boolean ok,他的get和set方法就会是isOK(),lombok将我的方法默认成一个字段了,这也算是lombok的bug