动态构建系统权限树 | 青训营笔记

88 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天

鉴权的一种简单方式就是判断用户有没有访问这个controller中的一个method的权限,只需要给用户分配就可以了。但是分配时的数据在哪来?可以写一个接口时就在数据表上手动添加,当然这不是很方便,能不能调用一个方法就可以直接自动生成系统权限树呢?答案显然是可以的。

本节记录我学习到的一种动态构建系统权限树的方法。思路大致就是扫描项目中带有@RestController注解的类,然后获取该类的所有方法,根据不同的需求再给它进行分级然后保存下来。

以下是扫描项目并保存的代码。结合了swagger,获取@Api或者@ApiOperation的内容,可对方法进行进一步的分类或者添加注释信息。

@Transactional(rollbackFor = Exception.class)
public void refreshSystemPrivilege() {
    privilegeService.remove(new LambdaQueryWrapper<>(null));
    RequestMappingHandlerMapping mapping = webApplicationContext.getBean(RequestMappingHandlerMapping.class);
    Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
    ArrayList<PrivilegeEntity> privilegeEntities = new ArrayList<>();
    HashSet<String> set = new HashSet<>();
    map.forEach((info, handlerMethod) -> {
        RestController restController =
                AnnotationUtils.findAnnotation(handlerMethod.getMethod().getDeclaringClass(), RestController.class);
        if (restController == null) {
            return;
        }
        RequestMapping requestMapping = AnnotationUtils.findAnnotation(handlerMethod.getMethod().getDeclaringClass(),
                RequestMapping.class);
        String fatherPath = "";
        if(requestMapping != null) {
            String[] value = requestMapping.value();
            if(value.length > 0) {
                fatherPath = fatherPath + value[0];
            }
        }

        Api api = AnnotationUtils.findAnnotation(handlerMethod.getMethod().getDeclaringClass(), Api.class);
        String apiDesc = "";
        if (api != null) {
            String[] tags = api.tags();
            if (tags.length > 0) {
                apiDesc = apiDesc + tags[0];
            }
        }

        Set<String> patterns = info.getPatternsCondition().getPatterns();
        if (CollectionUtils.isEmpty(patterns)) {
            return;
        }
        String className = (String) handlerMethod.getBean();
        String methodPerm = handlerMethod.getMethod().getName();
        List<String> list = SmartStringUtil.splitConvertToList(className, "\.");
        String controllerPerm = list.get(list.size() - 1);
        controllerPerm = firstLetterName(controllerPerm);
        String apiPerm = controllerPerm + "." + methodPerm;

        ApiOperation apiOperation = handlerMethod.getMethod().getAnnotation(ApiOperation.class);
        String methodComment = "";
        if (apiOperation != null) {
            methodComment = apiOperation.value();
            apiDesc = apiDesc + "-" + methodComment;
        }

        String[] split = apiDesc.split("-");
        if(split.length == 1) {
            return;
        }

        if(split.length == 2) {
            String fatherName = split[0] + "(" + controllerPerm + ")";
            if(set.add(fatherName)) {
                PrivilegeEntity father = new PrivilegeEntity();
                father.setParentName("0");
                father.setShowName(fatherName);
                privilegeEntities.add(father);
            }

            for(String url : patterns) {
                PrivilegeEntity privilegeEntity = new PrivilegeEntity();
                privilegeEntity.setPath(fatherPath + url);
                privilegeEntity.setApiPerm(apiPerm);
                privilegeEntity.setControllerPerm(controllerPerm);
                privilegeEntity.setMethodPerm(methodPerm);
                privilegeEntity.setDescription(apiDesc);
                privilegeEntity.setShowName(split[1] + "(" + methodPerm + ")");
                privilegeEntity.setParentName(split[0] + "(" + controllerPerm + ")");
                if (handlerMethod.getMethod().getAnnotation(NoNeedLogin.class) != null) {
                    privilegeEntity.setApiType(ApiTypeEnum.NO_NEED_LOGIN);
                    privilegeEntity.setShowName(privilegeEntity.getShowName() + NO_NEED_LOGIN);
                } else if (handlerMethod.getMethod().getAnnotation(NoValidPrivilege.class) != null) {
                    privilegeEntity.setApiType(ApiTypeEnum.NO_VALID_PRIVILEGE);
                    privilegeEntity.setShowName(privilegeEntity.getShowName() + NO_VALID_PRIVILEGE);
                } else if (handlerMethod.getMethod().getAnnotation(NotOpen.class) != null) {
                    privilegeEntity.setApiType(ApiTypeEnum.NOT_OPEN);
                    privilegeEntity.setShowName(privilegeEntity.getShowName() + NOT_OPEN);
                } else {
                    privilegeEntity.setApiType(ApiTypeEnum.VALID_PRIVILEGE);
                }
                privilegeEntities.add(privilegeEntity);
            }
        }

        if(split.length > 2) {
            for(int i = 0; i < split.length; i ++) {
                if(i == 0) {
                    if(set.add(split[0])) {
                        PrivilegeEntity father = new PrivilegeEntity();
                        father.setParentName("0");
                        father.setShowName(split[0]);
                        privilegeEntities.add(father);
                    }
                } else if(i == split.length - 2) {
                    if(set.add(split[i] + "(" + controllerPerm + ")")) {
                        PrivilegeEntity son = new PrivilegeEntity();
                        son.setShowName(split[i] + "(" + controllerPerm + ")");
                        son.setParentName(split[i - 1]);
                        privilegeEntities.add(son);
                    }
                } else if(i == split.length - 1) {
                    for(String url : patterns) {
                        PrivilegeEntity privilegeEntity = new PrivilegeEntity();
                        privilegeEntity.setPath(fatherPath + url);
                        privilegeEntity.setApiPerm(apiPerm);
                        privilegeEntity.setControllerPerm(controllerPerm);
                        privilegeEntity.setMethodPerm(methodPerm);
                        privilegeEntity.setDescription(apiDesc);
                        privilegeEntity.setShowName(split[i] + "(" + methodPerm + ")");
                        privilegeEntity.setParentName(split[i - 1] + "(" + controllerPerm + ")");
                        if (handlerMethod.getMethod().getAnnotation(NoNeedLogin.class) != null) {
                            privilegeEntity.setApiType(ApiTypeEnum.NO_NEED_LOGIN);
                            privilegeEntity.setShowName(privilegeEntity.getShowName() + NO_NEED_LOGIN);
                        } else if (handlerMethod.getMethod().getAnnotation(NoValidPrivilege.class) != null) {
                            privilegeEntity.setApiType(ApiTypeEnum.NO_VALID_PRIVILEGE);
                            privilegeEntity.setShowName(privilegeEntity.getShowName() + NO_VALID_PRIVILEGE);
                        } else if (handlerMethod.getMethod().getAnnotation(NotOpen.class) != null) {
                            privilegeEntity.setApiType(ApiTypeEnum.NOT_OPEN);
                            privilegeEntity.setShowName(privilegeEntity.getShowName() + NOT_OPEN);
                        } else {
                            privilegeEntity.setApiType(ApiTypeEnum.VALID_PRIVILEGE);
                        }
                        privilegeEntities.add(privilegeEntity);
                    }
                } else {
                    if(set.add(split[i])) {
                        PrivilegeEntity son = new PrivilegeEntity();
                        son.setShowName(split[i]);
                        son.setParentName(split[i - 1]);
                        privilegeEntities.add(son);
                    }
                }
            }
        }
    });
    privilegeService.saveBatch(privilegeEntities);
}

以下是构建权限树的方法。思路就是先从数据库查,然后构建树,同时缓存到项目运行内存中去。

private CopyOnWriteArrayList<PrivilegeViewDto> cachePrivilegeTree = Lists.newCopyOnWriteArrayList();
public void refreshSystemPrivilegeTree() {
    List<PrivilegeViewDto> privilegeViewDtos = privilegeDao.listAll();
    List<PrivilegeViewDto> tree = this.buildTree(privilegeViewDtos);
    cachePrivilegeTree.clear();
    cachePrivilegeTree.addAll(tree);
}

private List<PrivilegeViewDto> buildTree(List<PrivilegeViewDto> privilegeViewDtoList) {
    if(CollectionUtils.isEmpty(privilegeViewDtoList)) {
        return Lists.newArrayList();
    }
    List<PrivilegeViewDto> list =
            privilegeViewDtoList.stream().filter(f -> f.getParentName().equals("0")).collect(Collectors.toList());
    if(CollectionUtils.isEmpty(list)) {
        return Lists.newArrayList();
    }
    this.buildTree(list,privilegeViewDtoList);
    return list;
}

private void buildTree(List<PrivilegeViewDto> nodeList,List<PrivilegeViewDto> privilegeViewDtoList) {
    for(int i = 0; i < nodeList.size(); i ++) {
        PrivilegeViewDto node = nodeList.get(i);
        buildTree(node,privilegeViewDtoList);
    }
}

private void buildTree(PrivilegeViewDto node,List<PrivilegeViewDto> privilegeViewDtoList) {
    List<PrivilegeViewDto> children = getChildren(node, privilegeViewDtoList);
    if(CollectionUtils.isNotEmpty(children)) {
        node.setChildren(children);
        this.buildTree(children,privilegeViewDtoList);
    }
}

private List<PrivilegeViewDto> getChildren(PrivilegeViewDto node,List<PrivilegeViewDto> privilegeViewDtoList) {
    String showName = node.getShowName();
    return privilegeViewDtoList.stream().filter(f -> showName.equals(f.getParentName())).collect(Collectors.toList());
}