这是我参与「第五届青训营 」伴学笔记创作活动的第 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());
}