实现自己的权限管理系统(十一):角色用户模块、角色权限模块、权限过滤

前面弄了那么多,都是单独的模块。现在我们需要把用户和权限通过角色关联起来。

一、角色权限模块

1、角色的权限列表更新操作

public void changeRoleAcls(int roleId, List aclIdList) {
        //取出当前角色已分配的权限ID
        List originAclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(Lists.newArrayList(roleId));
        //判断下当前的originAclIdList 是否与 传进了的aclIdList相同
        //1.先判断下长度是否相等
        if (originAclIdList.size() == aclIdList.size()) {
            //用set存起来
            Set originAclIdSet = Sets.newHashSet(originAclIdList);
            Set aclIdSet = Sets.newHashSet(aclIdList);
            //移出权限
            originAclIdSet.removeAll(aclIdSet);
            if (CollectionUtils.isEmpty(originAclIdSet)) {
                //空,代表两个相同,不跟新
                return;
            }
        }
        //2.不相等则做更新操作
        updateRoleAcls(roleId, aclIdList);
        saveRoleAclLog(roleId, originAclIdList, aclIdList);

    }

    @Transactional
    public void updateRoleAcls(int roleId, List aclIdList) {
        //先删除原来权限
        sysRoleAclMapper.deleteByRoleId(roleId);

        if (CollectionUtils.isEmpty(aclIdList)) {
            return;
        }
        List roleAclList = Lists.newArrayList();
        for(Integer aclId : aclIdList) {
            SysRoleAcl roleAcl = SysRoleAcl.builder().roleId(roleId).aclId(aclId).operator(RequestHolder.getCurrentUser().getUsername())
                    .operateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest())).operateTime(new Date()).build();
            roleAclList.add(roleAcl);
        }
        //批量插入
        sysRoleAclMapper.batchInsert(roleAclList);
    }

二、角色用户模块

1、根据roleId查user:查出拥有这个角色的用户列表

     //根据roleId查user
    public List getListByRoleId(int roleId) {
        //1.获取userIdlist
        List userIdList = sysRoleUserMapper.getUserIdListByRoleId(roleId);
        if (CollectionUtils.isEmpty(userIdList)) {
            return Lists.newArrayList();
        }
        //2.通过idlist获取userlist
        return sysUserMapper.getByIdList(userIdList);

    }

2、如果角色的权限改变了,那么对应拥有该角色的用户权限也要改变想·

//如果角色的权限改变了,那么对应拥有该角色的用户权限也要改变
    public void changeRoleUsers(int roleId, List userIdList) {
        //1.获取原本的userIdList
        List originUserIdList = sysRoleUserMapper.getUserIdListByRoleId(roleId);
        //2.是否相同,不同就跟新
        if (originUserIdList.size() == userIdList.size()) {
            //用set存起来
            Set originAclIdSet = Sets.newHashSet(originUserIdList);
            Set aclIdSet = Sets.newHashSet(userIdList);
            //移出权限
            originAclIdSet.removeAll(aclIdSet);
            if (CollectionUtils.isEmpty(originAclIdSet)) {
                //空,代表两个相同,不跟新
                return;
            }
        }
        //2.不相等则做更新操作
        updateRoleUsers(roleId, userIdList);
        saveRoleUserLog(roleId, originUserIdList, userIdList);
    }

    @Transactional
    void updateRoleUsers(int roleId, List userIdList) {
        sysRoleUserMapper.deleteByRoleId(roleId);

        if (CollectionUtils.isEmpty(userIdList)) {
            return;
        }
        List roleUserList = Lists.newArrayList();
        for (Integer userId : userIdList) {
            SysRoleUser roleUser = SysRoleUser.builder().roleId(roleId).userId(userId).operator(RequestHolder.getCurrentUser().getUsername())
                    .operateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest())).operateTime(new Date()).build();
            roleUserList.add(roleUser);
        }
        sysRoleUserMapper.batchInsert(roleUserList);
    }

使用前面角色用户模块、角色权限模块:核心权限的获取

//(1)获取当前用户权限列表
    public List getCurrentUserAclList() {
        //1.拿到当前用户的ID
        int userId = RequestHolder.getCurrentUser().getId();
        //2.通过id去查权限列表
        return getUserAclList(userId);
    }

    //(1).2:通过id去查权限列表
    public List getUserAclList(int userId) {
        //如果是超级管理员,返回所有权限
        if (isSuperAdmin()) {
            return sysAclMapper.getAll();
        }
        //否则,通过UserId查角色Id列表:一个角色id有多个权限,一个用户id有多个角色id
        List userRoleIdList = sysRoleUserMapper.getRoleIdListByUserId(userId);
        if (CollectionUtils.isEmpty(userRoleIdList)) {
            return Lists.newArrayList();
        }
        //列表不为空,通过 角色ID列表 查询角色拥有的 权限ID集合
        List userAclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(userRoleIdList);
        if (CollectionUtils.isEmpty(userAclIdList)) {
            return Lists.newArrayList();
        }
        //通过权限ID集合去查权限
        return sysAclMapper.getByIdList(userAclIdList);
    }


	//(2) 获取当前角色所拥有权限列表
    public List getRoleAclList(int roleId) {
        //通过一个roleiId组一个roleId列表,通过列表去查权限列表
        List aclIdList = sysRoleAclMapper.getAclIdListByRoleIdList(Lists.newArrayList(roleId));
        if (CollectionUtils.isEmpty(aclIdList)) {
            return Lists.newArrayList();
        }
        return sysAclMapper.getByIdList(aclIdList);
    }

    public boolean isSuperAdmin() {
        // 这里是我自己定义了一个假的超级管理员规则,实际中要根据项目进行修改
        // 可以是配置文件获取,可以指定某个用户,也可以指定某个角色
        SysUser sysUser = RequestHolder.getCurrentUser();
        if (sysUser.getUsername().contains("admin")) {
            return true;
        }
        return false;
    }


	//***是否有权限访问URL
    public boolean hasUrlAcl(String url) {
        //是否为超级管理员
        if (isSuperAdmin()) {
            return true;
        }
        List aclList = sysAclMapper.getByUrl(url);
        if (CollectionUtils.isEmpty(aclList)) {
            return true;
        }

       List userAclList = getCurrentUserAclListFromCache();
       Set userAclIdSet = userAclList.stream().map(acl -> acl.getId()).collect(Collectors.toSet());

        boolean hasValidAcl = false;
        // 规则:只要有一个权限点有权限,那么我们就认为有访问权限
        for (SysAcl acl : aclList) {
            // 判断一个用户是否具有某个权限点的访问权限
            if (acl == null || acl.getStatus() != 1) { // 权限点无效
                continue;
            }
            hasValidAcl = true;
            if (userAclIdSet.contains(acl.getId())) {
                return true;
            }
        }
        if (!hasValidAcl) {
            return true;
        }
        return false;
    }


    public List getCurrentUserAclListFromCache() {
        int userId = RequestHolder.getCurrentUser().getId();
        String cacheValue = sysCacheService.getFromCache(CacheKeyConstants.USER_ACLS, String.valueOf(userId));
        //缓存中没有
        if (StringUtils.isBlank(cacheValue)) {
            //数据库取
            List aclList = getCurrentUserAclList();
            if (CollectionUtils.isNotEmpty(aclList)) {
                sysCacheService.saveCache(JsonMapper.obj2String(aclList), 600, CacheKeyConstants.USER_ACLS, String.valueOf(userId));
            }
            return aclList;
        }
        return JsonMapper.string2Obj(cacheValue, new TypeReference>() {
        });
    }
}

三、权限过滤:使用过滤器Filter

1、首先设置一个白名单:

某些请求路径不需要拦截:


    exclusionUrls
    /sys/user/noAuth.page,/login.page

读取配置文件中的URL,设置白名单
String exclusionUrls = filterConfig.getInitParameter("exclusionUrls");

2、不在白名单里的都进行拦截,若没有权限,做友好提示

//权限过滤
@Slf4j
public class AclControlFilter implements Filter {
	//定义全局变量set
    private static Set exclusionUrlSet = Sets.newConcurrentHashSet();

    private final static String noAuthUrl = "/sys/user/noAuth.page";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
		//读取配置文件中的URL,设置白名单
        String exclusionUrls = filterConfig.getInitParameter("exclusionUrls");
		//String --- List
        List exclusionUrlList = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(exclusionUrls);
		//List --  Set
        exclusionUrlSet = Sets.newConcurrentHashSet(exclusionUrlList);
        exclusionUrlSet.add(noAuthUrl);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String servletPath = request.getServletPath();
        Map requestMap = request.getParameterMap();
	//路径在白名单中,不拦截
        if (exclusionUrlSet.contains(servletPath)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
	//取当前登录用户
        SysUser sysUser = RequestHolder.getCurrentUser();
	//用户没登陆,设置无权限
        if (sysUser == null) {
            log.info("someone visit {}, but no login, parameter:{}", servletPath, JsonMapper.obj2String(requestMap));
            noAuth(request, response);
            return;
        }
	//从spring上下文中取bean,通过SysCoreService的方法来判断是否有权限访问这个URL
        SysCoreService sysCoreService = ApplicationContextHelper.popBean(SysCoreService.class);
        if (!sysCoreService.hasUrlAcl(servletPath)) {
            log.info("{} visit {}, but no permission, parameter:{}", JsonMapper.obj2String(sysUser), servletPath, JsonMapper.obj2String(requestMap));
            noAuth(request, response);
            return;
        }

        filterChain.doFilter(servletRequest, servletResponse);
        return;
    }
    //无权限访问处理方法
       private void noAuth(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String servletPath = request.getServletPath();
        //json请求
        if (servletPath.endsWith(".json")) {
            JsonData jsonData = JsonData.fail("没有访问权限,如需要访问,请联系管理员");
            response.setHeader("Content-Type", "application/json");
            response.getWriter().print(JsonMapper.obj2String(jsonData));
            return;
        //无权限访问跳转页面
        } else {
            clientRedirect(noAuthUrl, response);
            return;
        }
    }

    private void clientRedirect(String url, HttpServletResponse response) throws IOException{
        response.setHeader("Content-Type", "text/html");
        response.getWriter().print("\n"
                + "\n" + "\n" + "\n"
                + "跳转中...\n" + "\n" + "\n" + "跳转中,请稍候...\n" + "\n" + "\n" + "\n");
    }

    @Override
    public void destroy() {

    }
}

四、在SysRoleController中添加角色与权限点的关系、角色与用户的关系

//保存角色与权限点的关系
    @RequestMapping("/changeAcls.json")
    @ResponseBody
    public JsonData changeAcls(
            @RequestParam("roleId") int roleId,
            @RequestParam(value = "aclIds", required = false, defaultValue = "") String aclIds) {
        List aclIdList = StringUtil.splitToListInt(aclIds);
        sysRoleAclService.changeRoleAcls(roleId, aclIdList);
        return JsonData.success();
    }

    //保存角色与用户的关系
    @RequestMapping("/changeUsers.json")
    @ResponseBody
    public JsonData changeUsers(
            @RequestParam("roleId") int roleId,
            @RequestParam(value = "userIds", required = false, defaultValue = "") String userIds) {
        //把UserId转为list
        List userIdList = StringUtil.splitToListInt(userIds);
        sysRoleUserService.changeRoleUsers(roleId, userIdList);
        return JsonData.success();
    }


    //加载角色用户数据
    @RequestMapping("/users.json")
    @ResponseBody
    public JsonData users(@RequestParam("roleId") int roleId) {
        //通过roleId获取Userlist
        List selectedUserList = sysRoleUserService.getListByRoleId(roleId);
        //获取所有的user,然后减去前面获取的,就剩下没有获取的
        List allUserList = sysUserService.getAll();
        List unselectedUserList = Lists.newArrayList();
        //优化for循环
        Set selectedUserIdSet =
                selectedUserList.stream().map(sysUser -> sysUser.getId()).collect(Collectors.toSet());
        //如果是有效的并且在未选中的列表中就添加
        for(SysUser sysUser : allUserList) {
            if (sysUser.getStatus() == 1 && !selectedUserIdSet.contains(sysUser.getId())) {
                unselectedUserList.add(sysUser);
            }
        }
        /*当选择的用户的状态已经无效就不展示,使用流式过滤
        selectedUserList = selectedUserList.stream().filter(sysUser -> sysUser.getStatus() != 1).collect(Collectors.toList());
        */
        Map> map = Maps.newHashMap();
        map.put("selected", selectedUserList);
        map.put("unselected", unselectedUserList);
        return JsonData.success(map);
    }

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(实现自己的权限管理系统)