jyy
2021-06-27 6e783f279e7b1dd1f0fc243d7d8504ede0b25870
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
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;
        }
 
        if (userFunction == null) {
            return false;
        } else {
 
            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);
        if (userFunction == null) {
            return false;
        } else {
            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);
                }
 
            }
        }
    }
 
}