| package com.matrix.system.common.authority; | 
|   | 
| import cn.hutool.crypto.SecureUtil; | 
| import cn.hutool.json.JSONArray; | 
| import cn.hutool.json.JSONObject; | 
| import cn.hutool.json.JSONUtil; | 
| import com.matrix.component.redis.RedisClient; | 
| import com.matrix.core.constance.MatrixConstance; | 
| import com.matrix.core.pojo.AjaxResult; | 
| import com.matrix.core.tools.StringUtils; | 
| import com.matrix.core.tools.WebUtil; | 
| import com.matrix.system.common.authority.strategy.LoginStrategy; | 
| import com.matrix.system.common.bean.SysFnBtnRel; | 
| import com.matrix.system.common.bean.SysFunction; | 
| import com.matrix.system.common.bean.SysUsers; | 
| import com.matrix.system.common.constance.AppConstance; | 
| import com.matrix.system.common.service.SysFunctionService; | 
| import org.apache.commons.collections.CollectionUtils; | 
| import org.springframework.beans.factory.annotation.Autowired; | 
| import org.springframework.stereotype.Component; | 
|   | 
| import java.util.*; | 
| import java.util.Map.Entry; | 
|   | 
| /** | 
|  * DefaultAuthorityManager 实现了权限控制接口 | 
|  * | 
|  * @author JIANGYOUYAO | 
|  * @email 935090232@qq.com | 
|  * @date 2017年12月6日 | 
|  */ | 
| @Component("defaultAuthorityManager") | 
| public class DefaultAuthorityManager implements AuthorityManager { | 
|   | 
|     private static final int DEFAULT_2 = 2; | 
|   | 
|     public static final String USER_POWER_REDISKEY = "USER_POWER_"; | 
|     public static final String USER_POWER_REDISKEY_PC = "USER_POWER_PC"; | 
|   | 
|     @Autowired | 
|     SysFunctionService sysFunctionService; | 
|   | 
|     public static final String USERFUNCTION = "userFunction"; | 
|     public static final String MENUSFUNCTION = "menusFunction"; | 
|     /** | 
|      * 用户所有路径权限的记录 | 
|      **/ | 
|     public static final String USER_URL_MAPPING = "userUrlMapping"; | 
|   | 
|     @Autowired | 
|     RedisClient redisClient; | 
|   | 
|     private DefaultAuthorityManager() { | 
|     } | 
|   | 
|     public <T> T login(LoginStrategy loginStrategy) { | 
|         @SuppressWarnings("unchecked") | 
|         T user = (T) loginStrategy.login(); | 
|         WebUtil.setSessionAttribute(MatrixConstance.LOGIN_KEY, user); | 
|         WebUtil.setSessionAttribute(AppConstance.DEFAULT_AUTHORITYMANAGER, this); | 
|         return user; | 
|     } | 
|   | 
|     @Override | 
|     public void getLoginOut() { | 
|         WebUtil.getSession().removeAttribute(MatrixConstance.LOGIN_KEY); | 
|     } | 
|   | 
|     /** | 
|      * 判断用户是否具有按钮功能 | 
|      * | 
|      * @param matchStr | 
|      * @return | 
|      * @throws IllegalArgumentException | 
|      */ | 
|     @Override | 
|     public boolean isBtnPermitted(String matchStr) { | 
|         // 开发人员和超级管理员具有所有权限 | 
|         SysUsers user = WebUtil.getSessionAttribute(MatrixConstance.LOGIN_KEY); | 
|   | 
|         Map<String, SysFunction> userFunction = WebUtil.getSessionAttribute(USERFUNCTION); | 
|         // 企业管理员不校验按钮权限 | 
|         if (AppConstance.USER_TYPE_DEVELOPER.equals(user.getSuUserType()) | 
|                 || AppConstance.USER_TYPE_SUPER.equals(user.getSuUserType()) | 
|                 || AppConstance.USER_TYPE_ADMIN.equals(user.getSuUserType())) { | 
|             return true; | 
|         } | 
|         String[] strs = matchStr.split("-"); | 
|         if (strs.length != DEFAULT_2) { | 
|             throw new IllegalArgumentException("权限matchStr格式错误,需要fnCode:btnValue"); | 
|         } | 
|   | 
|         SysFunction fn = userFunction.get(strs[0].trim()); | 
|         // 功能是否存在 | 
|         if (fn == null) { | 
|             return false; | 
|         } else { | 
|             return StringUtils.isContentSet(strs[1].trim(), fn.getRpfBns()); | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * 判断用户是否具有功能权限 | 
|      * | 
|      * @return | 
|      */ | 
|     @Override | 
|     public boolean isFnPermitted(String fnCode) { | 
|         // 开发人员和超级管理员具有所有权限 | 
|         SysUsers user = WebUtil.getSessionAttribute(MatrixConstance.LOGIN_KEY); | 
|         if (AppConstance.USER_TYPE_DEVELOPER.equals(user.getSuUserType()) | 
|                 || AppConstance.USER_TYPE_SUPER.equals(user.getSuUserType())) { | 
|             return true; | 
|         } | 
|         Map<String, SysFunction> userFunction = WebUtil.getSessionAttribute(USERFUNCTION); | 
|         SysFunction fn = userFunction.get(fnCode); | 
|         return fn == null ? false : true; | 
|     } | 
|   | 
|     /** | 
|      * 初始化用户权限 | 
|      * | 
|      * @param result | 
|      * @author JIANGYOUYAO | 
|      * @email 935090232@qq.com | 
|      * @date 2017年12月5日 | 
|      */ | 
|     public void initUserPower(AjaxResult result) { | 
|   | 
|         // 记录用户所有的功能 | 
|         Map<String, SysFunction> userFunction = new HashMap<>(MatrixConstance.COLLECTION_SIZE); | 
|   | 
|         // 用户的一级菜单权限 | 
|         List<SysFunction> menuFunction = new ArrayList<>(); | 
|   | 
|         // | 
|         List<String> userUrlMapping = new ArrayList<>(); | 
|   | 
|         // 用户的所有功能权限用id记录,方便后面查询菜单树形结构 | 
|         Map<String, SysFunction> menuFunctionMap = new TreeMap<>(); | 
|   | 
|         SysUsers sysUser = WebUtil.getSessionAttribute(MatrixConstance.LOGIN_KEY); | 
|   | 
|         String redisKey = USER_POWER_REDISKEY_PC + SecureUtil.md5(sysUser.getSuId()+""); | 
|         String cachedValue = redisClient.getCachedValue(redisKey); | 
|         if (StringUtils.isNotBlank(cachedValue)) { | 
|             //从缓存中获取用户权限 | 
|             JSONObject powerMap = JSONUtil.parseObj(cachedValue); | 
|             String userFunctionMapStr = powerMap.get(USERFUNCTION).toString(); | 
|             JSONObject userFunctionMap = JSONUtil.parseObj(userFunctionMapStr); | 
|             Set<String> userFunctionMapKeys = userFunctionMap.keySet(); | 
|             userFunctionMapKeys.forEach(key -> { | 
|                 userFunction.put(key, userFunctionMap.get(key, SysFunction.class)); | 
|             }); | 
|             String menusFunctionListStr = powerMap.get(MENUSFUNCTION).toString(); | 
|             JSONArray menusFunctionArray = JSONUtil.parseArray(menusFunctionListStr); | 
|             for (int i = 0; i < menusFunctionArray.size(); i++) { | 
|                 menuFunction.add(menusFunctionArray.get(i, SysFunction.class)); | 
|             } | 
|             String userUrlMappingListStr = powerMap.get(USER_URL_MAPPING).toString(); | 
|             JSONArray userUrlMappingArray = JSONUtil.parseArray(userUrlMappingListStr); | 
|             for (int i = 0; i < userUrlMappingArray.size(); i++) { | 
|                 userUrlMapping.add(userUrlMappingArray.get(i, String.class)); | 
|             } | 
|         } else { | 
|             // 获取用户所有权限 | 
|             getUserFunction(userFunction, menuFunctionMap, userUrlMapping); | 
|   | 
|             // 组装菜单 | 
|             assembleMenu(menuFunction, menuFunctionMap); | 
|   | 
|             Map<String ,Object> powerMap=new HashMap<>(); | 
|             powerMap.put(USERFUNCTION, userFunction); | 
|             powerMap.put(MENUSFUNCTION, menuFunction); | 
|             powerMap.put(USER_URL_MAPPING, userUrlMapping); | 
|             redisClient.saveValue(redisKey,JSONUtil.parseObj(powerMap,true)); | 
|         } | 
|   | 
|   | 
|         // 把用户菜单和用户的功能都存在session中。 | 
|         WebUtil.setSessionAttribute(USERFUNCTION, userFunction); | 
|         WebUtil.setSessionAttribute(MENUSFUNCTION, menuFunction); | 
|         WebUtil.setSessionAttribute(USER_URL_MAPPING, userUrlMapping); | 
|         result.putInMap(USERFUNCTION, userFunction); | 
|         result.putInMap(MENUSFUNCTION, menuFunction); | 
|   | 
|     } | 
|   | 
|     /** | 
|      * 获取用的功能,包括菜单功能和非菜单功能 | 
|      * | 
|      * @param userFunctionMap | 
|      * @param menuFunctionMap | 
|      * @param userUrlMapping | 
|      * @author JIANGYOUYAO | 
|      * @email 935090232@qq.com | 
|      * @date 2017年12月5日 | 
|      */ | 
|     private void getUserFunction(Map<String, SysFunction> userFunctionMap, Map<String, SysFunction> menuFunctionMap, | 
|                                  List<String> userUrlMapping) { | 
|         SysUsers sysUser = WebUtil.getSessionAttribute(MatrixConstance.LOGIN_KEY); | 
|         // 判断用户类型 | 
|         if (AppConstance.USER_TYPE_ADMIN.equals(sysUser.getSuUserType())) { | 
|             // 管理员拥有公司全部权限 | 
|             List<SysFunction> tempList = sysFunctionService.findCompanyFunction(sysUser.getCompanyId()); | 
|   | 
|             // 区分菜单和非菜单功能 | 
|             for (SysFunction sysFunction : tempList) { | 
|   | 
|                 userFunctionMap.put(sysFunction.getFnCode(), sysFunction); | 
|                 // 注册访问路径 | 
|                 registerUrlMapping(userUrlMapping, sysFunction, true); | 
|   | 
|                 // 如果是菜单功能单独记录 | 
|                 if (AppConstance.IS_Y.equals(sysFunction.getFnShowMenu())) { | 
|                     menuFunctionMap.put(sysFunction.getFnId() + "", sysFunction); | 
|                 } | 
|             } | 
|         } else if (AppConstance.USER_TYPE_EMPLOYEE.equals(sysUser.getSuUserType())) { | 
|             // 普通员工账号只拥有自己所拥有的权限 | 
|             List<SysFunction> userFunctionList = sysFunctionService.findFunctionByRoleIds(sysUser.getRoleIds()); | 
|             for (SysFunction sysFunction : userFunctionList) { | 
|                 // TODO注册访问路径 | 
|                 registerUrlMapping(userUrlMapping, sysFunction, false); | 
|   | 
|   | 
|                 if (userFunctionMap.containsKey(sysFunction.getFnCode())) { | 
|                     // 如果功能已经被添加到集合中则追加权限按钮 | 
|                     SysFunction oneFunctionInMap = userFunctionMap.get(sysFunction.getFnCode()); | 
|                     // 为了方便判断所以用字符串记录一下 | 
|                     if (StringUtils.isBlank(oneFunctionInMap.getRpfBns())) { | 
|                         oneFunctionInMap.setRpfBns(sysFunction.getRpfBns()); | 
|                     } else { | 
|                         oneFunctionInMap.setRpfBns(oneFunctionInMap.getRpfBns() + "," + sysFunction.getRpfBns()); | 
|                     } | 
|                 } else { | 
|                     // 如果是新功能则直接添加 | 
|   | 
|                     userFunctionMap.put(sysFunction.getFnCode(), sysFunction); | 
|                     if (AppConstance.IS_Y.equals(sysFunction.getFnShowMenu())) { | 
|                         menuFunctionMap.put(sysFunction.getFnId() + "", sysFunction); | 
|                     } | 
|                 } | 
|             } | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * 注册功能和按钮的访问路径 | 
|      * | 
|      * @param userUrlMapping | 
|      * @param sysFunction | 
|      * @author JIANGYOUYAO | 
|      * @email 935090232@qq.com | 
|      * @date 2017年12月8日 | 
|      */ | 
|     private void registerUrlMapping(List<String> userUrlMapping, SysFunction sysFunction, boolean isAdmin) { | 
|         String path = sysFunction.getFnPath(); | 
|         if (StringUtils.isNotBlank(path) && !userUrlMapping.contains(path)) { | 
|             userUrlMapping.add(path); | 
|         } | 
|         // 注册按钮路径 | 
|         List<SysFnBtnRel> btnRels = sysFunction.getSysFnBtnRel(); | 
|         if (CollectionUtils.isNotEmpty(btnRels)) { | 
|             for (SysFnBtnRel sysFnBtnRel : btnRels) { | 
|                 //公司管理员可以添加所有按钮权限否则只能添加员工自己所有拥有的权限 | 
|                 if (isAdmin || StringUtils.isContentSet(sysFnBtnRel.getBtnValue(), sysFunction.getRpfBns())) { | 
|                     String btnPath = sysFnBtnRel.getFbPath(); | 
|                     if (StringUtils.isNotBlank(btnPath) && !userUrlMapping.contains(btnPath)) { | 
|                         userUrlMapping.add(btnPath); | 
|                     } | 
|                 } | 
|             } | 
|         } | 
|     } | 
|   | 
|     /** | 
|      * 把菜单组装成树形结构 | 
|      * | 
|      * @param menuFunction | 
|      * @param menuFunctionMap | 
|      * @author JIANGYOUYAO | 
|      * @email 935090232@qq.com | 
|      * @date 2017年12月5日 | 
|      */ | 
|     private void assembleMenu(List<SysFunction> menuFunction, Map<String, SysFunction> menuFunctionMap) { | 
|         // 将map.entrySet()转换成list,并按照功能的FnSequence倒序 | 
|         List<Entry<String, SysFunction>> list = new ArrayList<>(menuFunctionMap.entrySet()); | 
|         Collections.sort(list, new Comparator<Entry<String, SysFunction>>() { | 
|             @Override | 
|             public int compare(Entry<String, SysFunction> o1, Entry<String, SysFunction> o2) { | 
|                 Integer a = o1.getValue().getFnSequence() == null ? 0 : o1.getValue().getFnSequence(); | 
|                 Integer b = o2.getValue().getFnSequence() == null ? 0 : o2.getValue().getFnSequence(); | 
|                 return Integer.compare(b, a); | 
|             } | 
|         }); | 
|         // 获取菜单权限,思路:如果遍历map如果功能存在父节点,就找到父节点然后把子节点加入进去,这样就只需要遍历一次 | 
|         for (Entry<String, SysFunction> entry : list) { | 
|             String id = entry.getKey(); | 
|   | 
|             SysFunction function = menuFunctionMap.get(id); | 
|             // 如果是一级节点则直接存入菜单 | 
|             if (null == function.getFnParentId() || 0L == function.getFnParentId()) { | 
|                 menuFunction.add(function); | 
|             } else { | 
|                 // 非一级节点找到父节点后存入 | 
|                 SysFunction parentFn = menuFunctionMap.get(String.valueOf(function.getFnParentId())); | 
|                 if (parentFn != null) { | 
|                     List<SysFunction> childs = parentFn.getChilds(); | 
|                     if (childs == null) { | 
|                         parentFn.setChilds(new ArrayList<SysFunction>()); | 
|                     } | 
|                     parentFn.getChilds().add(function); | 
|                 } | 
|   | 
|             } | 
|         } | 
|     } | 
|   | 
| } |