Skip to content

权限管理

AIFlowy 是基于 RBAC 的权限控制,用户可以精确控制到按钮级别的权限。

权限框架为 sa-token(v1.40.0)

crud 权限拦截

基础的 crud 接口被提取到 tech.aiflowy.common.web.controller.BaseCurdController 中去了。

其中包含了 listpagedetailsaveupdateremoveremoveBatchintelligentFilling 等接口。

按照功能划分为 querysaveremove 三种权限。新增功能模块时,需要在菜单中配置这几样基础权限,否则会被拦截器拦截并提示 无权操作

统一处理 crud 权限的拦截器为:tech.aiflowy.auth.config.CurdInterceptor

代码如下:

java
public class CurdInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String groupName = "";
        // 检查handler是否是HandlerMethod类型
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;

            // 获取类上的特定注解
            UsePermission classAnnotation = handlerMethod.getBeanType().getAnnotation(UsePermission.class);
            if (classAnnotation != null) {
                // 处理注解逻辑
                groupName = classAnnotation.moduleName();
            }
            // 有此注解,交给 sa token 自行判断
            SaCheckPermission saCheckPermission = handlerMethod.getMethodAnnotation(SaCheckPermission.class);
            if (saCheckPermission != null) {
                return true;
            }
        }
        String requestUri = request.getRequestURI();
        // 查询
        String finalGroupName = groupName;
        SaRouter.match("/**/list",
                "/**/page",
                "/**/detail",
                "/**/intelligentFilling"
        ).check(r -> {
            checkBaseCurd(requestUri, finalGroupName, "query");
        });
        // 保存
        SaRouter.match("/**/save",
                "/**/update"
        ).check(r -> {
            checkBaseCurd(requestUri, finalGroupName, "save");
        });
        // 删除
        SaRouter.match("/**/remove",
                "/**/removeBatch"
        ).check(r -> {
            checkBaseCurd(requestUri, finalGroupName, "remove");
        });

        return true;
    }

    private void checkBaseCurd(String uri, String groupName, String permission) {
        int idx = uri.lastIndexOf("/");
        String per = uri.substring(0,idx + 1) + permission;
        if (StrUtil.isNotEmpty(groupName)) {
            // 如果指定了继承的模块,就改为该模块的权限校验
            per = groupName + "/" + permission;
        }
        StpUtil.checkPermission(per);
    }
}

权限继承

某些功能模块存在子项,比如定时任务模块,它的子项则是定时任务日志模块。

但是日志模块又不需要出现在菜单中,因此没法赋予用户日志模块的权限,访问接口时会被拦截器拦截。

这时就可以用权限继承 @UsePermission 来让用户获得定时任务的权限时同时具备日志的权限。

在定时任务日志的控制器类上加上注解即可,代码如下:

java
@RestController
@RequestMapping("/api/v1/sysJobLog")
@UsePermission(moduleName = "/api/v1/sysJob") // 继承定时任务的权限
public class SysJobLogController extends BaseCurdController<SysJobLogService, SysJobLog> {
    public SysJobLogController(SysJobLogService service) {
        super(service);
    }

    @Override
    protected Result onSaveOrUpdateBefore(SysJobLog entity, boolean isSave) {
        LoginAccount loginUser = SaTokenUtil.getLoginAccount();
        if (isSave) {
            commonFiled(entity,loginUser.getId(),loginUser.getTenantId(), loginUser.getDeptId());
        }
        return super.onSaveOrUpdateBefore(entity, isSave);
    }
}

业务接口的权限控制

除了基础的增删改查接口,平时会写很多业务接口,如果需要对这些接口进行权限控制。

直接使用 sa-token@SaCheckPermission 注解即可。

需要注意的是,由于拦截器拦截 crud 时是通过接口后缀来判断的。因此写业务接口时要避免使用这些后缀: listpagedetailsaveupdateremoveremoveBatchintelligentFilling