7.0 KiB
在上小节 中,我们为 Gateway 网关添加了全局异常处理器,实现了接口出参格式的统一。但是,依然还存在一个小问题 —— 提示信息不够友好。
登录校验不通过,提示不友好问题
接下来,演示一下登录校验不通过,提示不友好的问题。当我们调用登出接口,并且未携带 Token 令牌,如下图所示:
可以看到,提示信息为权限不足。这个提示信息不够友好,应该提示请先登录,或者未携带 Token 令牌之类,这个提示,会让调用者一脸闷逼状态~
同时,观察网关服务的控制台日志,如下所示,从全局异常处理器打印的异常信息分析,明显是检测到了未提交 Token 令牌的问题,只不过需要对 SaTokenException 异常进行细化处理,而不是统一都返回权限不足提示:
SaToken 异常
在 SaToken 框架中,SaTokenException 是一个非常核心的异常,诸如未登录异常、权限不足异常、不具备对应角色异常,均继承于它:
-- SaTokenException
-- NotLoginException // 未登录异常
-- NotPermissionException // 权限不足异常
-- NotRoleException // 不具备对应角色异常
-- ...
抛出异常
在上小节中,我们在 SaToken 配置类中,将 .setError() 方法删除掉了,此时,当登录校验不通过、权限校验不通过等情况,SaToken 都会统一抛出一个 SaTokenException 父异常,这会导致全局异常处理器无法判断具体的异常类型:
再次将 .setError() 方法添加上,并抛出具体异常类型,代码如下:
package com.quanxiaoha.xiaohashu.gateway.auth;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author: 犬小哈
* @date: 2024/6/13 14:48
* @version: v1.0.0
* @description: [Sa-Token 权限认证] 配置类
**/
@Configuration
public class SaTokenConfigure {
// 注册 Sa-Token全局过滤器
@Bean
public SaReactorFilter getSaReactorFilter() {
return new SaReactorFilter()
// 拦截地址
.addInclude("/**") /* 拦截全部path */
// 鉴权方法:每次访问进入
.setAuth(obj -> {
// 省略..
})
// 异常处理方法:每次setAuth函数出现异常时进入
.setError(e -> {
// return SaResult.error(e.getMessage());
// 手动抛出异常,抛给全局异常处理器
if (e instanceof NotLoginException) { // 未登录异常
throw new NotLoginException(e.getMessage(), null, null);
} else if (e instanceof NotPermissionException || e instanceof NotRoleException) { // 权限不足,或不具备角色,统一抛出权限不足异常
throw new NotPermissionException(e.getMessage());
} else { // 其他异常,则抛出一个运行时异常
throw new RuntimeException(e.getMessage());
}
})
;
}
}
解释一下
setError()方法中的逻辑:
NotLoginException: 当用户未登录时,手动抛出NotLoginException异常;NotPermissionException和NotRoleException: 权限不足,或不具备对应角色,统一抛出权限不足异常;- 其他异常,则手动抛出一个运行时异常;
异常处理
接着,编辑 GlobalExceptionHandler 全局异常处理器,对不同的异常类型,返回不同的错误提示,代码如下:
// 省略...
// 根据捕获的异常类型,设置不同的响应状态码和响应消息
if (ex instanceof NotLoginException) { // 未登录异常
// 设置 401 状态码
response.setStatusCode(HttpStatus.UNAUTHORIZED);
// 构建响应结果
result = Response.fail(ResponseCodeEnum.UNAUTHORIZED.getErrorCode(), "未携带 Token 令牌");
} else if (ex instanceof NotPermissionException) { // 无权限异常
// 权限认证失败时,设置 401 状态码
response.setStatusCode(HttpStatus.UNAUTHORIZED);
// 构建响应结果
result = Response.fail(ResponseCodeEnum.UNAUTHORIZED.getErrorCode(), ResponseCodeEnum.UNAUTHORIZED.getErrorMessage());
} else { // 其他异常,则统一提示 “系统繁忙” 错误
result = Response.fail(ResponseCodeEnum.SYSTEM_ERROR);
}
// 省略...
测试一波
登录校验不通过
编码完成后,重启网关服务。测试一波登出接口,先在请求头中不添加 Token 令牌,如下图所示,可以看到这次提示信息就正常了:未携带 Token 令牌:
权限校验不通过
再来测试一下权限校验不通过的情况,由于已经配置了登出接口必须具有 admin 角色才能请求,而目前登录的用户只具备普通角色:
携带上 Token 令牌请求接口,效果如下:
成功提示权限不足。至此,网关服务的认证鉴权提示就相对比较友好了,后续如果还有调整的地方,我们再来改。OK, 本小节优化完毕~
补充:令牌过期提示问题
2024.6.22 补充:测试的时候,漏掉了令牌过期的问题,当令牌过期时,提示如下:
提示信息依然还有问题,当令牌失效时,SaToken 同样会抛出 NotLoginException,如下图所示:
这就不能写死提示为:未携带令牌了,干脆直接用异常本身的错误信息,修改 GlobalExceptionHandler 全局异常处理器如下:
if (ex instanceof NotLoginException) { // 未登录异常
// 设置 401 状态码
response.setStatusCode(HttpStatus.UNAUTHORIZED);
// 构建响应结果
result = Response.fail(ResponseCodeEnum.UNAUTHORIZED.getErrorCode(), ex.getMessage());
}
修改完毕后,重启网关再次测试,提示信息就正常了~