package com.matrix.system.app.authority; import cn.hutool.crypto.SecureUtil; 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.AuthorityManager; 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.init.LocalCache; 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; import java.util.stream.Collectors; /** * DefaultAuthorityManager 实现了权限控制接口 * * @author JIANGYOUYAO * @email 935090232@qq.com * @date 2017年12月6日 */ @Component public class AppAuthorityManager implements AuthorityManager { private static final int DEFAULT_2 = 2; @Autowired SysFunctionService sysFunctionService; public static final String USER_POWER_REDISKEY_APP = "USER_POWER_APP"; public static final String USERFUNCTION = "userFunction"; /** 用户所有路径权限的记录 **/ public static final String USER_URL_MAPPING = "userUrlMapping"; private AppAuthorityManager() { } public 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) { throw new UnsupportedOperationException("未实现"); } /** * 判断用户是否具有功能权限 * @return */ @Override public boolean isFnPermitted(String fnCode) { throw new UnsupportedOperationException("未实现"); } /** * 初始化用户权限 * * @author JIANGYOUYAO * @email 935090232@qq.com * @date 2017年12月5日 * @param result * @param user */ public void initUserPower(AjaxResult result, SysUsers user) { // 记录用户所有的功能 Map userFunction = new HashMap<>(MatrixConstance.COLLECTION_SIZE); // List userUrlMapping = new ArrayList<>(); String redisKey = USER_POWER_REDISKEY_APP + SecureUtil.md5(user.getSuId()+""); Map cachePowerMap = LocalCache.get(redisKey); if (Objects.nonNull(cachePowerMap)) { userFunction = (Map) cachePowerMap.get(USERFUNCTION); userUrlMapping = (List) cachePowerMap.get(USER_URL_MAPPING); } else { // 获取用户所有权限 getUserFunction(user,userFunction, userUrlMapping); Map powerMap=new HashMap<>(); powerMap.put(USERFUNCTION, userFunction); powerMap.put(USER_URL_MAPPING, userUrlMapping); LocalCache.save(redisKey,powerMap); } WebUtil.setSessionAttribute(USERFUNCTION, userFunction); WebUtil.setSessionAttribute(USER_URL_MAPPING, userUrlMapping); result.putInMap(USERFUNCTION, userFunction); } /** * 获取用的功能,包括菜单功能和非菜单功能 * * @author JIANGYOUYAO * @email 935090232@qq.com * @date 2017年12月5日 * @param userFunctionMap * @param userUrlMapping */ private void getUserFunction(SysUsers sysUser, Map userFunctionMap, List userUrlMapping) { // 判断用户类型 if (AppConstance.USER_TYPE_ADMIN.equals(sysUser.getSuUserType())) { // 管理员拥有公司全部权限 List tempList = sysFunctionService.findCompanyFunction(sysUser.getCompanyId()); // 区分菜单和非菜单功能 for (SysFunction sysFunction : tempList) { userFunctionMap.put(sysFunction.getFnCode(), sysFunction); // 注册访问路径 registerUrlMapping(userUrlMapping, sysFunction,true); } } else if (AppConstance.USER_TYPE_EMPLOYEE.equals(sysUser.getSuUserType())) { // 普通员工账号只拥有自己所拥有的权限 List userFunctionList = sysFunctionService.findFunctionByRoleIds(sysUser.getRoleIds()); for (SysFunction sysFunction : userFunctionList) { sysFunction.setSysFnBtnRel( sysFunction.getSysFnBtnRel().stream().filter(item->StringUtils.isContentSet(item.getBtnValue(),sysFunction.getRpfBns())).collect(Collectors.toList()) ); // 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); } } } } /** * 注册功能和按钮的访问路径 * * @author JIANGYOUYAO * @email 935090232@qq.com * @date 2017年12月8日 * @param userUrlMapping * @param sysFunction */ private void registerUrlMapping(List userUrlMapping, SysFunction sysFunction, boolean isAdmin) { String path = sysFunction.getFnPath(); if (StringUtils.isNotBlank(path) && !userUrlMapping.contains(path)) { userUrlMapping.add(path); } // 注册按钮路径 List 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); } } } } } /** * 把菜单组装成树形结构 * * @author JIANGYOUYAO * @email 935090232@qq.com * @date 2017年12月5日 * @param menuFunction * @param menuFunctionMap */ private void assembleMenu(List menuFunction, Map menuFunctionMap) { // 将map.entrySet()转换成list,并按照功能的FnSequence倒序 List> list = new ArrayList<>(menuFunctionMap.entrySet()); Collections.sort(list, new Comparator>() { @Override public int compare(Entry o1, Entry 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 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 childs = parentFn.getChilds(); if (childs == null) { parentFn.setChilds(new ArrayList()); } parentFn.getChilds().add(function); } } } } }