介绍sa-token实际应用的高阶用法。
定义配置类SaTokenConfigure->实现WebMvcConfigurer,设置一个只对login请求放通的拦截器:
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor(handle-> StpUtil.checkLogin()))
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
}
测试结果:
我们在未登录的情况下,此时cookie值为空,访问其他接口则返回NotLoginException异常(通常情况下我们可以做个全局异常捕获,如果获取到该异常则用统一格式返回,这里不做详细描述,可以参考:实现全局异常处理):
登录成功之后,cookie值存在,访问其他接口正常:
至此,我们一个简单的登录拦截器就已经实现了。
其实我们可以继续进行优化,使用sa-token封装的SaRouter路由写法使得更容易定义,具体SaRouter的用法可以参考官网-校验函数详解,以下仅为官网示例:
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SaInterceptor(Handler -> {
// 等同于下方的简写写法
// SaRouter
// // 拦截的path列表 支持写多个
// .match("/**")
// // 排除掉的path 支持写多个
// .notMatch("/login")
// // 要执行的校验动作
// .check(r -> StpUtil.checkLogin());
// 可以简写登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
SaRouter.match("/**", "/login", r -> StpUtil.checkLogin());
// 角色校验 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证
SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));
// 根据路由划分模块,不同模块不同鉴权
SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
}));
}
}
接下来我们介绍如何将自定义的角色和权限标识与sa-token结合在一起。
首先我们需要定义一个StpInterfaceImpl -> 实现StpInterface接口,需要实现两个方法分别是getPermissionList,getRoleList,此处需要注意的是只要配置了角色或者权限标识的拦截,那么每一次请求都会访问这两个方法,可以考虑做个缓存,以避免频繁请求用户信息:
@Component
public class StpInterfaceImpl implements StpInterface {
/**
* 返回一个账号所拥有的权限码集合
* @param loginId 账号id
* @param loginType 账号类型
* @return
*/
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
// 此处通常对接用户权限表根据loginId查询对应用户的权限信息。此处仅作模拟loginId="1" 则拥有order权限标识,否则没有
if ("1".equals(loginId)){
return Arrays.asList("orders");
}else {
return Arrays.asList("default");
}
}
/**
* 返回一个账号所拥有的角色标识集合
* @param loginId 账号id
* @param loginType 账号类型
* @return
*/
@Override
public List<String> getRoleList(Object loginId, String loginType) {
// 此处通常对接用户角色表根据loginId查询对应用户的角色标识信息。此处仅作模拟loginId="666" 表示管理员,否则非管理员
if ("666".equals(loginId)){
return Arrays.asList("admin");
}else {
return Arrays.asList("general");
}
}
}
结合上一章节中的配置信息,我们创建对应的controller进行测试:
// 角色校验 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证
SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));
// 根据路由划分模块,不同模块不同鉴权
SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
@RestController
@RequestMapping("/admin")
public class AdminController {
@GetMapping("/test")
public String test(){
return "admin角色允许访问";
}
}
我们用usId=“2”,即表示没有管理员角色进行访问/admin/test,结果如下表示该用户无此角色被拒:
我们用usId=“666”,即表示管理员角色进行访问/admin/test,结果如下表示用户具备该角色请求放通:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AUzuMozV-1671439109823)(null)]
@RestController
@RequestMapping("/orders")
public class AdminController {
@GetMapping("/test")
public String test(){
return "orders权限标识允许访问";
}
}
我们用usId=“2”,即表示没有管理员角色进行访问/orders/test,结果如下表示该用户无此权限被拒:
我们用usId=“1”,即表示管理员角色进行访问/orders/test,结果如下表示用户具备该权限请求放通:
那每一个权限标识或者角色我们都要手动配置到配置类中吗,有没有更加简便的方法在我们写controller就对应好角色和标识的关系。
这里我们需要了解两个注解:
此时我们只需要在管控的controller对应位置上加上注解就能完成配置类中的功能,加在类名上表示该controller下的所有入口遵从认证标识:
@SaCheckRole("admin")
@RestController
@RequestMapping("/admin")
public class AdminController {
// 所有的请求都需要满足角色admin...
}
@RestController
@RequestMapping("/admin")
public class AdminController {
// 只有该请求需要满足角色admin
@SaCheckRole("admin")
@GetMapping("/testAnno")
public String testAnno(){
return "注解方式实现角色放通";
}
}
同理,权限标识也是如此:
@SaCheckPermission("orders")
@RestController
@RequestMapping("/orders")
public class OrderController {
// 所有的请求都需要满足权限标识orders...
}
@RestController
@RequestMapping("/orders")
public class OrderController {
@SaCheckPermission("orders")
@GetMapping("/test")
public String test(){
return "orders权限标识允许访问";
}
}
若存在需要多个权限或者角色标识来判断的情况,我们可以使用如下写法:
// 同时具备大括号中的所有权限标识才放通
@SaCheckPermission({"user-add", "user-delete", "user-update"})
// 只要具备其中一个权限标识就可以进入
@SaCheckPermission(value = {"user-add", "user-delete", "user-update"}, mode = SaMode.OR)
角色注解同理:
// 同时具备大括号中的所有角色才放通
@SaCheckRole({"admin", "my-role"})
// 只要具备其中一个角色就可以进入
@SaCheckRole(value = {"admin", "my-role"}, mode = SaMode.OR)
还有其他相关注解,例如:
参考资料: