任何系统都离不开权限管理,一般来说,要实现权限管理,需要有三个模块。
1、资源:包含系统中所有可用的功能。
2、权限:针对资源,对资源的访问添加控制方式。
3、角色:针对权限,对权限的打包。
这里讲一下我的实现,因为用到了反射,IO,自定义注解,集合等知识点,觉得对于java的初学者来说很经典,所以分享出来。
先上思路:
1、Resource类:
private String name;
private String url;
private String controller;
Map<String,List<String> modules = new HashMap<>();
modules.add(packageName(包全限定名),controllersClassName(类全限定名));
1)、通过项目中controller包的全限定名,获取该包下所有类的全限定名(注解判断是否添加controller类,类别名)。
2)、根据controller类的全限定名,获取该类下所有方法名(注解判断是否添加该方法,方法别名),然后持久化resource对象。
package test.yuf.ResourceImpl;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import test.yuf.annotation.TabResource;
import test.yuf.domain.Resource;
//假设为Resource的业务层实现类
public class ResourceImpl {
//创建一个包名和包下controller类的map
private static Map<String,List<String>> modules = new HashMap<>();
//1)、通过项目中controller包的全限定名,获取该包下所有类的全限定名(注解判断是否添加controller类,类别名)。
public static void loadPackage(String[] packages) throws ClassNotFoundException{
for (String string : packages) {
URL url = Thread.currentThread().getContextClassLoader().getResource(string.replace(".", "/"));
File file = new File(url.getFile());
String[] classNames = file.list();
List<String> ControllerNames = new ArrayList<>();
for (String string2 : classNames) {
String allName = string+"."+string2.substring(0, string2.length()-6);
//判断controller类是否有注解
boolean isAnnotation = Class.forName(allName).isAnnotationPresent(TabResource.class);
if(isAnnotation){
ControllerNames.add(allName);
}
}
modules.put(string, ControllerNames);
}
}
//2)、根据controller类的全限定名,获取该包下所有方法名(注解判断是否添加该方法,方法别名),然后持久化resource对象。
public static List<Resource> importController(String module) throws ClassNotFoundException{
List<Resource> resources = new ArrayList<>();
Class<?> clz = Class.forName(module);
//获取类别名
TabResource ctab = clz.getAnnotation(TabResource.class);
String controllerAlias = "".equals(ctab.value())?clz.getName():ctab.value();
Method[] methods = clz.getDeclaredMethods();
for (Method method : methods) {
if(method.isAnnotationPresent(TabResource.class)){
//获取方法别名
TabResource tab = method.getAnnotation(TabResource.class);
String methodAlias = controllerAlias+":"+!"".equals(tab.value()) != null?tab.value():method.getName();
String methodName = module+":"+method.getName();
//模拟数据库持久化操作.....
Resource resource = new Resource();
resource.setController(module);
resource.setName(methodAlias);
resource.setUrl(methodName);
resources.add(resource);
}
}
return resources;
}
public static Map<String,List<String>> getModules(){
return modules;
}
//测试
public static void main(String[] args) throws ClassNotFoundException {
String[] packages = {"test.yuf.controller"};
loadPackage(packages);
Map<String,List<String>> modules = getModules();
System.out.println(modules);
for (String string : modules.keySet()) {
List<String> controllers = modules.get(string);
for (String string2 : controllers) {
System.out.println(importController(string2));
}
}
}
}
2、Permission类:
private String name;
private String resource;
根据选择的资源,导入到权限类
3、Role类:
private String name;
//多对多关系
private List<Permission> permissions = new ArrayList<>();
根据给该角色分配的权限,创建角色和权限的关联。
关于请求是否有限的判断(通常写在上下文对象中):
public static boolean checkUserPermission(String resource) {
//如果是超级管理员,直接放行
if(getUser().getId()==1){
return true;
}
//1、验证资源是否有权限(是否有锁)
Permission dbPermission = permissionService.getPermissionByResource(resource);
if(dbPermission == null){
return true;
}else{
//2、验证用户是否有对应的权限(是否有钥匙)
//1)获取当前登录用户的所有权限,权限也需要缓存,所以用用户上下文工具UserContext
List<Permission> userPermisisons = UserContext.getUsersPermission(getUser());
//2)把用户的权限,一一和当前访问的资源权限进行比对
//比对细节权限
for (Permission userPermission : userPermisisons) {
if(userPermission.getId() == dbPermission.getId()){
return true;//存在则放行
}
}
//比对all权限
String allResource = resource.split(":")[0]+":ALL";//获取all资源地址
for (Permission userPermission : userPermisisons) {
//比较资源地址
if(allResource.equals(userPermission.getResource())){
return true;
}
}
}
//3、如果都没有匹配,那么返回false,拦截器请求
return false;
}