权限控制
引言
早在刚实习的时候,接触到的一个项目中涉及到了用户的权限管理控制,当时觉得很厉害,并且完全看不懂,当时的那个项目采用的是Jfinal框架,但如今自己要做一个项目了,打算采用SpringBoot来做,其中后台管理也需要权限来控制,因此在积攒了一年的经验后开始尝试接触这些东西了,今天就来说一下后台管理的权限控制吧!
思路
我认为权限管理总共分为三个步骤:
1、项目启动的时候
2、用户登录的时候
3、用户操作相应模块的时候


权限设计思路流程
业务流程
如上面两张图所示为我的思路,下面讲一下具体的实现过程!
一、新建一个PermissionScanner类继承CommandLineRunner
@Component
public class PermissionScanner implements CommandLineRunner {
@Autowired
private ModuleMapper moduleMap;
@Autowired
private MethodMapper methodMapper;
@Override
public void run(String... args) throws Exception {
//扫描所有controller,注册权限模块和方法
new AddPermission().scanner(moduleMap, methodMapper);
System.out.println("扫描了所有controller,项目启动了!");
}
}
二、新建一个添加权限的类
@Component
public class AddPermission {
private List<Class<? extends Controller>> excludeClasses = Lists.newArrayList();
private boolean includeAllJarsInLib;
private List<String> includeJars = Lists.newArrayList();
private String suffix = "Controller";
public AddPermission addExcludeClasses(Class<? extends Controller>... clazzes) {
if (clazzes != null) {
for (Class<? extends Controller> clazz : clazzes) {
excludeClasses.add(clazz);
}
}
return this;
}
public AddPermission addExcludeClasses(List<Class<? extends Controller>> clazzes) {
excludeClasses.addAll(clazzes);
return this;
}
public AddPermission addJars(String... jars) {
if (jars != null) {
for (String jar : jars) {
includeJars.add(jar);
}
}
return this;
}
public AddPermission includeAllJarsInLib(boolean includeAllJarsInLib) {
this.includeAllJarsInLib = includeAllJarsInLib;
return this;
}
public AddPermission suffix(String suffix) {
this.suffix = suffix;
return this;
}
//扫描controller包下面的所有方法
public void scanner(ModuleMapper moduleMap, MethodMapper methodMapper){
List<Class<? extends RestController>> controllerClasses = ClassSearcher.of(RestController.class)
.includeAllJarsInLib(includeAllJarsInLib).injars(includeJars).search();
PermissionModule permissionController = null;
for (Class controller : controllerClasses) {
if (excludeClasses.contains(controller)) {
continue;
}
permissionController = (PermissionModule) controller.getAnnotation(PermissionModule.class);
if (permissionController != null) {
Module module = new Module();
module.setControllerkey(controllerKey(controller));
module.setModuleName(permissionController.text());
moduleMap.insertSelective(module);
Method[] methods = controller.getMethods();
for (Method method : methods) {
/*
* 根据注解类型返回方法的指定类型注解
*/
PermissionMethod permissionMethod = method.getAnnotation(PermissionMethod.class);
if (permissionMethod != null) {
com.beardream.model.Method m = new com.beardream.model.Method();
m.setMethodName(permissionMethod.text());
m.setActionkey(controllerKey(controller) + methodKey(method.getName()));
m.setModuleId(module.getModuleId());
System.out.println(methodMapper.insertSelective(m));
}
}
}
}
}
private String controllerKey(Class<Controller> clazz) {
Preconditions.checkArgument(clazz.getSimpleName().endsWith(suffix),
clazz.getName() + " is not annotated with @ControllerBind and not end with " + suffix);
if (clazz.getPackage().getName().startsWith("com.beardream")) {
String controllerKey = "/" + TextUtil.firstCharToLowerCase(clazz.getSimpleName());
controllerKey = controllerKey.substring(0, controllerKey.indexOf(suffix));
return controllerKey;
}
String controllerKey = "/" + TextUtil.firstCharToLowerCase(clazz.getSimpleName());
controllerKey = controllerKey.substring(0, controllerKey.indexOf(suffix));
return controllerKey;
}
private String methodKey(String methodname) {
String controllerKey = "/" + TextUtil.firstCharToLowerCase(methodname);
return controllerKey;
}
}
三、扫描包下所有Controller类,将其加到集合中
- 核心代码
public <T> List<Class<? extends T>> search() {
List<String> classFileList = Lists.newArrayList();
if (scanPackages.isEmpty()) {
classFileList = findFiles(classpath, "*.class");
} else {
for (String scanPackage : scanPackages) {
classFileList = findFiles(classpath + File.separator + scanPackage.replaceAll("\\.", "\\" + File.separator), "*.class");
}
}
classFileList.addAll(findjarFiles(libDir));
return extraction(target, classFileList);
}
private static List<String> findFiles(String baseDirName, String targetFileName) {
/**
* 算法简述: 从某个给定的需查找的文件夹出发,搜索该文件夹的所有子文件夹及文件, 若为文件,则进行匹配,匹配成功则加入结果集,若为子文件夹,则进队列。 队列不空,重复上述操作,队列为空,程序结束,返回结果。
*/
List<String> classFiles = Lists.newArrayList();
File baseDir = new File(baseDirName);
if (!baseDir.exists() || !baseDir.isDirectory()) {
} else {
String[] files = baseDir.list();
for (int i = 0; i < files.length; i++) {
File file = new File(baseDirName + File.separator + files[i]);
if (file.isDirectory()) {
classFiles.addAll(findFiles(baseDirName + File.separator + files[i], targetFileName));
} else {
if (wildcardMatch(targetFileName, file.getName())) {
String fileName = file.getAbsolutePath();
String open = PathKit.getRootClassPath() + File.separator;
String close = ".class";
int start = fileName.indexOf(open);
int end = fileName.indexOf(close, start + open.length());
System.out.println("++++++++++++++++++++"+fileName.substring(start + open.length(), end)+":"+File.separator);
String guize="";
if ("\\".equals(File.separator)) {
guize="\\\\";
}else{
guize=File.separator;
}
String className = fileName.substring(start + open.length(), end).replaceAll(guize, ".");
classFiles.add(className);
}
}
}
}
return classFiles;
}
重点注意一下面这个方法
private static <T> List<Class<? extends T>> extraction(Class<T> clazz, List<String> classFileList) {
List<Class<? extends T>> classList = Lists.newArrayList();
for (String classFile : classFileList) {
Class<?> classInFile = Reflect.on(classFile).get();
//在Jfinal中,通过判断这个类是否集成了Controller来判断他是不是控制器进行筛选
// 但在这里是spring环境,因此应该判断他是否有RestController
/* 这段是Jfinal中的代码
if (classInFile.isAssignableFrom(clazz) && classInFile == clazz){
classList.add((Class<? extends T>) classInFile);
}
*/
Annotation[] annotations=classInFile.getAnnotations();
for (int i=0;i<annotations.length;i++){
if (annotations[i].annotationType().getTypeName().hashCode() == clazz.getTypeName().hashCode()){
classList.add((Class<? extends T>) classInFile);
}
}
}
return classList;
}
在注释中已经标明,Jfinal的所有控制器都是继承了Controller,因此它在这里判断这个类是不是Controller的子类来决定他是不是Controller,但在Spring或SpringBoot中,它是通过注解@RestController或者@Controller来表明这个类是一个控制器,因此我们稍作修改,判断了它是否有RestController注解来判断。也对应了上面AddPermission类中的下面这行代码
List<Class<? extends RestController>> controllerClasses = ClassSearcher.of(RestController.class)
.includeAllJarsInLib(includeAllJarsInLib).injars(includeJars).search();
介绍到这里差不多核心的东西也已经介绍完了,剩下的就只有当用户登录时查询他拥有的权限以及在操作的时候来判断用户的权限是否对应了。
后续
第一次写简书,以前都是看其他大牛的博客文章,如今是自己第一次来写,可能表述的不是很清楚,希望各位童鞋指正,也可以在下方评论留言。
如果大家需要的话后面又介绍用户登录时查询他拥有的权限以及在操作的时候来判断用户的权限是否对应。
代码参考了JFinal中的一些代码...
网友评论