ruoyi-vue-pro路由管理:动态路由与权限控制

ruoyi-vue-pro路由管理:动态路由与权限控制

【免费下载链接】ruoyi-vue-pro 🔥 官方推荐 🔥 RuoYi-Vue 全新 Pro 版本,优化重构所有功能。基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 微信小程序,支持 RBAC 动态权限、数据权限、SaaS 多租户、Flowable 工作流、三方登录、支付、短信、商城、CRM、ERP、AI 大模型等功能。你的 ⭐️ Star ⭐️,是作者生发的动力! 【免费下载链接】ruoyi-vue-pro 项目地址: https://gitcode.com/GitHub_Trending/ruoy/ruoyi-vue-pro

在企业级后台管理系统中,路由管理和权限控制是核心功能模块。ruoyi-vue-pro作为一款基于Spring Boot + Vue的前后端分离架构项目,提供了完整的动态路由和精细化权限控制解决方案。本文将深入解析其实现原理和最佳实践。

🎯 核心架构设计

ruoyi-vue-pro采用RBAC(Role-Based Access Control,基于角色的访问控制)模型,实现了菜单、按钮级别的精细化权限控制。整体架构如下图所示:

mermaid

权限模型设计

mermaid

🔐 后端权限控制实现

1. 权限服务核心逻辑

ruoyi-vue-pro的后端权限控制通过PermissionServiceImpl类实现,主要包含以下核心方法:

// 判断用户是否拥有任意权限
@Override
public boolean hasAnyPermissions(Long userId, String... permissions) {
    if (ArrayUtil.isEmpty(permissions)) return true;
    
    // 获取用户有效角色
    List<RoleDO> roles = getEnableUserRoleListByUserIdFromCache(userId);
    if (CollUtil.isEmpty(roles)) return false;
    
    // 遍历权限判断
    for (String permission : permissions) {
        if (hasAnyPermission(roles, permission)) return true;
    }
    
    // 超管权限检查
    return roleService.hasAnySuperAdmin(convertSet(roles, RoleDO::getId));
}

// 角色菜单权限分配
@Override
@DSTransactional
@Caching(evict = {
    @CacheEvict(value = RedisKeyConstants.MENU_ROLE_ID_LIST, allEntries = true),
    @CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, allEntries = true)
})
public void assignRoleMenu(Long roleId, Set<Long> menuIds) {
    // 计算新增和删除的菜单
    Set<Long> dbMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleId), RoleMenuDO::getMenuId);
    Set<Long> menuIdList = CollUtil.emptyIfNull(menuIds);
    
    Collection<Long> createMenuIds = CollUtil.subtract(menuIdList, dbMenuIds);
    Collection<Long> deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIdList);
    
    // 执行数据库操作
    if (CollUtil.isNotEmpty(createMenuIds)) {
        roleMenuMapper.insertBatch(createMenuIds.stream()
            .map(menuId -> new RoleMenuDO(roleId, menuId))
            .collect(Collectors.toList()));
    }
    if (CollUtil.isNotEmpty(deleteMenuIds)) {
        roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds);
    }
}

2. 数据权限控制

ruoyi-vue-pro支持多种数据权限范围,通过DataScopeEnum定义:

数据范围描述
ALL1所有数据权限
DEPT_CUSTOM2自定义部门数据权限
DEPT_ONLY3本部门数据权限
DEPT_AND_CHILD4本部门及以下数据权限
SELF5仅本人数据权限
// 数据权限获取实现
@Override
@DataPermission(enable = false)
public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) {
    List<RoleDO> roles = getEnableUserRoleListByUserIdFromCache(userId);
    DeptDataPermissionRespDTO result = new DeptDataPermissionRespDTO();
    
    if (CollUtil.isEmpty(roles)) {
        result.setSelf(true);
        return result;
    }
    
    // 遍历角色计算数据权限
    for (RoleDO role : roles) {
        switch (DataScopeEnum.getByScope(role.getDataScope())) {
            case ALL:
                result.setAll(true);
                break;
            case DEPT_CUSTOM:
                result.getDeptIds().addAll(role.getDataScopeDeptIds());
                break;
            case DEPT_ONLY:
                result.getDeptIds().add(userDeptId.get());
                break;
            case DEPT_AND_CHILD:
                result.getDeptIds().addAll(deptService.getChildDeptIdListFromCache(userDeptId.get()));
                break;
            case SELF:
                result.setSelf(true);
                break;
        }
    }
    return result;
}

🚀 前端动态路由实现

1. 路由初始化流程

前端动态路由的生成遵循以下流程:

mermaid

2. 权限指令实现

前端通过自定义指令v-permission实现按钮级别的权限控制:

// 权限指令实现
const permission = {
  mounted(el, binding) {
    const { value } = binding
    const roles = store.getters.roles
    
    if (value && value instanceof Array && value.length > 0) {
      const permissionRoles = value
      const hasPermission = roles.some(role => {
        return permissionRoles.includes(role)
      })
      
      if (!hasPermission) {
        el.parentNode && el.parentNode.removeChild(el)
      }
    } else {
      throw new Error(`需要权限角色! Like v-permission="['admin','editor']"`)
    }
  }
}

// 全局注册
app.directive('permission', permission)

3. 路由守卫配置

路由守卫确保用户在访问页面时具备相应权限:

// 路由守卫实现
router.beforeEach(async (to, from, next) => {
  // 设置页面title
  document.title = getPageTitle(to.meta.title)
  
  // 确定用户是否已登录
  const hasToken = getToken()
  
  if (hasToken) {
    if (to.path === '/login') {
      next({ path: '/' })
    } else {
      const hasRoles = store.getters.roles && store.getters.roles.length > 0
      if (hasRoles) {
        next()
      } else {
        try {
          // 获取用户信息
          const { roles } = await store.dispatch('user/getInfo')
          
          // 根据角色生成可访问的路由
          const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
          
          // 动态添加路由
          accessRoutes.forEach(route => {
            router.addRoute(route)
          })
          
          // 确保addRoutes已完成
          next({ ...to, replace: true })
        } catch (error) {
          // 移除token并跳转到登录页
          await store.dispatch('user/resetToken')
          next(`/login?redirect=${to.path}`)
        }
      }
    }
  } else {
    // 未登录的处理逻辑
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next(`/login?redirect=${to.path}`)
    }
  }
})

📊 缓存优化策略

ruoyi-vue-pro采用Redis缓存优化权限查询性能:

缓存Key描述过期策略
PERMISSION_MENU_ID_LIST:{permission}权限对应的菜单ID列表菜单变更时清除
MENU_ROLE_ID_LIST:{menuId}菜单对应的角色ID列表角色权限变更时清除
USER_ROLE_ID_LIST:{userId}用户对应的角色ID列表用户角色变更时清除
// 缓存配置示例
@Cacheable(value = RedisKeyConstants.USER_ROLE_ID_LIST, key = "#userId")
public Set<Long> getUserRoleIdListByUserIdFromCache(Long userId) {
    return getUserRoleIdListByUserId(userId);
}

@Cacheable(value = RedisKeyConstants.MENU_ROLE_ID_LIST, key = "#menuId")
public Set<Long> getMenuRoleIdListByMenuIdFromCache(Long menuId) {
    return convertSet(roleMenuMapper.selectListByMenuId(menuId), RoleMenuDO::getRoleId);
}

🔧 最佳实践指南

1. 权限配置流程

mermaid

2. 权限标识规范

建议遵循统一的权限标识命名规范:

  • 模块:操作:资源
  • 例如:system:user:createsystem:menu:query

3. 数据权限配置

数据权限配置表结构:

字段名类型描述
role_idbigint角色ID
data_scopeint数据范围类型
data_scope_dept_idsvarchar自定义部门ID列表

🎯 性能优化建议

  1. 缓存策略:合理使用Redis缓存权限数据,减少数据库查询
  2. 懒加载:路由组件按需加载,提升首屏加载速度
  3. 批量操作:权限分配时使用批量操作,减少数据库IO
  4. 索引优化:为权限相关表建立合适的索引

📝 总结

ruoyi-vue-pro的动态路由和权限控制体系提供了完整的企业级解决方案:

  • 精细化控制:支持菜单、按钮、数据多维度权限控制
  • 高性能:通过Redis缓存和优化查询提升系统性能
  • 易扩展:模块化设计便于功能扩展和定制
  • 安全可靠:完善的权限校验机制保障系统安全

通过本文的深入解析,开发者可以更好地理解ruoyi-vue-pro的权限控制机制,并在实际项目中灵活运用,构建安全可靠的后台管理系统。

【免费下载链接】ruoyi-vue-pro 🔥 官方推荐 🔥 RuoYi-Vue 全新 Pro 版本,优化重构所有功能。基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 微信小程序,支持 RBAC 动态权限、数据权限、SaaS 多租户、Flowable 工作流、三方登录、支付、短信、商城、CRM、ERP、AI 大模型等功能。你的 ⭐️ Star ⭐️,是作者生发的动力! 【免费下载链接】ruoyi-vue-pro 项目地址: https://gitcode.com/GitHub_Trending/ruoy/ruoyi-vue-pro

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值