首页
/ JeeSite路由与权限管理:构建安全的企业级应用架构

JeeSite路由与权限管理:构建安全的企业级应用架构

2026-02-04 05:21:12作者:房伟宁

本文详细介绍了JeeSite Vue3前端框架在企业级应用中的路由与权限管理解决方案。系统基于Vue Router 4.x构建动态路由架构,通过权限守卫实现路由拦截和验证,采用模块化设计将路由配置与权限管理深度集成。文章涵盖了动态路由的核心架构、权限守卫实现机制、路由数据结构设计、动态路由构建流程、组件动态加载策略,以及多层次的权限控制方案,包括路由级别、组件级别、菜单级别和API级别的权限控制。同时深入探讨了多租户架构下的数据隔离技术实现,包括数据库层面的多种隔离策略、租户标识传递机制和数据访问层的租户过滤方案,为企业级应用提供了全面的安全架构设计。

Vue Router 4.x动态路由配置与实现

在现代企业级应用开发中,动态路由是实现权限控制和模块化架构的核心技术。JeeSite Vue3前端采用Vue Router 4.x作为路由管理解决方案,通过精心的架构设计实现了灵活高效的路由动态加载机制。

动态路由的核心架构

JeeSite的动态路由系统基于Vue Router 4.x的addRouteAPI构建,采用模块化设计理念,将路由配置与权限管理深度集成。系统通过权限守卫(Permission Guard)在用户登录后动态构建并添加路由,实现按需加载。

flowchart TD
    A[用户访问页面] --> B{权限守卫拦截}
    B -->|白名单路由| C[直接放行]
    B -->|需要认证| D{检查Token有效性}
    D -->|无效Token| E[重定向到登录页]
    D -->|有效Token| F{是否已获取用户信息}
    F -->|未获取| G[获取用户信息和权限]
    F -->|已获取| H{是否已添加动态路由}
    H -->|未添加| I[构建动态路由并添加]
    H -->|已添加| J[正常导航]
    I --> K[重定向到目标页面]

权限守卫的实现机制

权限守卫是动态路由系统的核心,它通过router.beforeEach钩子函数实现路由拦截和权限验证:

// 权限守卫核心逻辑
export function createPermissionGuard(router: Router) {
  const userStore = useUserStoreWithOut();
  const permissionStore = usePermissionStoreWithOut();
  
  router.beforeEach(async (to, from, next) => {
    // 白名单路由直接放行
    if (whitePathList.includes(to.path as PageEnum)) {
      next();
      return;
    }

    // Token验证失败重定向到登录页
    if (!token) {
      const redirectData = {
        path: LOGIN_PATH,
        replace: true,
        query: to.path ? { redirect: to.path } : undefined
      };
      next(redirectData);
      return;
    }

    // 动态路由构建和添加
    if (!permissionStore.getIsDynamicAddedRoute) {
      const routes = await permissionStore.buildRoutesAction();
      routes.forEach((route) => {
        router.addRoute(route as unknown as RouteRecordRaw);
      });
      router.addRoute(PAGE_NOT_FOUND_ROUTE);
      permissionStore.setDynamicAddedRoute(true);
    }

    next();
  });
}

路由数据结构设计

JeeSite采用标准化的路由数据结构,确保动态路由的灵活性和可维护性:

// 应用路由记录类型定义
export interface AppRouteRecordRaw {
  path: string;
  name?: string;
  meta?: RouteMeta;
  redirect?: string;
  component: Component | string;
  children?: AppRouteRecordRaw[];
  alias?: string | string[];
  props?: Record<string, any>;
  beforeEnter?: NavigationGuardWithThis<undefined>;
  fullPath?: string;
}

路由元数据(RouteMeta)包含丰富的权限控制信息:

// 路由元数据接口
export interface RouteMeta {
  title: string;           // 路由标题
  ignoreAuth?: boolean;    // 是否忽略权限验证
  roles?: RoleEnum[];      // 可访问的角色
  hideMenu?: boolean;      // 是否隐藏菜单
  hideBreadcrumb?: boolean;// 是否隐藏面包屑
  icon?: string;          // 菜单图标
  frameSrc?: string;      // iframe源地址
  currentActiveMenu?: string; // 当前激活菜单
}

动态路由构建流程

权限存储(Permission Store)负责构建动态路由,其核心方法buildRoutesAction实现了路由的动态生成:

// 权限存储中的路由构建方法
class PermissionStore {
  async buildRoutesAction(): Promise<AppRouteRecordRaw[]> {
    // 1. 获取后端返回的菜单数据
    const menuList = await getMenuList();
    
    // 2. 将菜单数据转换为路由配置
    const routes = this.transformMenuToRoutes(menuList);
    
    // 3. 排序并处理路由层级关系
    return this.sortRoutes(routes);
  }

  private transformMenuToRoutes(menuList: Menu[]): AppRouteRecordRaw[] {
    return menuList.map(menu => ({
      path: menu.path,
      name: menu.name,
      component: this.getComponent(menu.component),
      meta: {
        title: menu.title,
        icon: menu.icon,
        hideMenu: menu.hidden,
        roles: menu.roles
      },
      children: menu.children ? this.transformMenuToRoutes(menu.children) : []
    }));
  }
}

路由组件动态加载

JeeSite采用Vite的动态导入特性实现路由组件的按需加载,显著提升应用性能:

// 组件动态加载映射表
const componentMap = new Map<string, () => Promise<Component>>();

// 注册动态组件
componentMap.set('Layout', () => import('@jeesite/core/layouts/default/index.vue'));
componentMap.set('Iframe', () => import('@jeesite/core/layouts/iframe/index.vue'));
componentMap.set('BasicForm', () => import('@jeesite/core/components/Form/index.vue'));

// 根据组件名称获取动态导入函数
function getComponent(componentName: string): () => Promise<Component> {
  return componentMap.get(componentName) || 
         () => import(`@jeesite/core/views/${componentName}.vue`);
}

路由配置示例

以下是一个完整的路由配置示例,展示了JeeSite中典型的路由结构:

// 基础路由配置示例
export const basicRoutes: AppRouteRecordRaw[] = [
  {
    path: '/',
    name: 'Root',
    redirect: '/dashboard',
    component: LAYOUT,
    meta: {
      title: 'Root',
      hideMenu: true
    },
    children: [
      {
        path: 'dashboard',
        name: 'Dashboard',
        component: () => import('@jeesite/core/views/dashboard/index.vue'),
        meta: {
          title: '控制台',
          icon: 'ion:grid-outline'
        }
      }
    ]
  },
  {
    path: '/system',
    name: 'System',
    component: LAYOUT,
    meta: {
      title: '系统管理',
      icon: 'ion:settings-outline'
    },
    children: [
      {
        path: 'user',
        name: 'UserManagement',
        component: () => import('@jeesite/core/views/system/user/index.vue'),
        meta: {
          title: '用户管理',
          roles: ['admin']
        }
      }
    ]
  }
];

路由权限控制策略

JeeSite实现了多层次的路由权限控制机制,确保系统安全性:

控制层级 实现方式 应用场景
路由级别 动态路由添加 模块权限控制
组件级别 权限指令v-auth 按钮级权限控制
菜单级别 元数据hideMenu 菜单可见性控制
API级别 接口权限验证 数据操作权限控制
// 权限指令实现
export const authDirective = {
  mounted(el: HTMLElement, binding: DirectiveBinding<string>) {
    const { value } = binding;
    const permissionStore = usePermissionStoreWithOut();
    
    if (value && !permissionStore.getAuthStatus(value)) {
      el.parentNode?.removeChild(el);
    }
  }
};

性能优化策略

为确保动态路由系统的性能,JeeSite采用了多项优化措施:

  1. 路由懒加载:所有路由组件均采用动态导入
  2. 路由缓存:已添加的路由状态进行缓存,避免重复构建
  3. 代码分割:基于模块的路由分组,优化打包体积
  4. 预加载策略:关键路由组件进行预加载
// 路由预加载策略
function preloadCriticalRoutes() {
  // 预加载布局组件和常用页面
  import('@jeesite/core/layouts/default/index.vue');
  import('@jeesite/core/views/dashboard/index.vue');
  
  // 根据用户角色预加载可能访问的模块
  const userRoles = useUserStore().getUserInfo.roles;
  if (userRoles.includes('admin')) {
    import('@jeesite/core/views/system/user/index.vue');
  }
}

通过上述架构设计和实现,JeeSite的Vue Router 4.x动态路由系统提供了强大而灵活的权限管理能力,为企业级应用的安全性和可维护性奠定了坚实基础。

菜单权限与按钮权限的精细化控制

在企业级应用开发中,权限控制是保障系统安全性的核心环节。JeeSite框架提供了完善的菜单权限与按钮权限精细化控制机制,通过统一的权限模型和灵活的配置方式,实现了从路由级别到组件级别的全方位权限管理。

权限控制架构设计

JeeSite采用基于Pinia状态管理的权限控制架构,通过统一的权限存储模块和指令系统,实现了前后端一致的权限验证机制。

flowchart TD
    A[用户登录] --> B[获取权限信息]
    B --> C[构建动态路由]
    C --> D[初始化权限存储]
    D --> E[路由权限守卫]
    E --> F[组件权限指令]
    F --> G[界面渲染控制]

权限数据模型

系统采用分层的权限标识符设计,支持模块:功能:操作的三级权限控制:

权限层级 示例 说明
模块权限 sys 系统管理模块
功能权限 sys:menu 菜单管理功能
操作权限 sys:menu:edit 菜单编辑操作

动态路由构建机制

JeeSite支持三种权限模式,通过PermissionModeEnum进行配置:

export enum PermissionModeEnum {
  ROLE = 'ROLE',           // 基于角色权限
  BACK = 'BACK',           // 后端动态权限
  ROUTE_MAPPING = 'ROUTE_MAPPING'  // 路由映射权限
}

核心的路由构建逻辑在buildRoutesAction方法中实现:

async buildRoutesAction(): Promise<AppRouteRecordRaw[]> {
  const userStore = useUserStore();
  const roleList = toRaw(userStore.getRoleList) || [];
  
  // 路由过滤函数
  const routeFilter = (route: AppRouteRecordRaw) => {
    const { meta } = route;
    const { roles } = meta || {};
    if (!roles) return true;
    return roleList.some((role) => roles.includes(role));
  };
  
  // 根据权限模式构建路由
  switch (permissionMode) {
    case PermissionModeEnum.ROLE:
      routes = filter(asyncRoutes, routeFilter);
      break;
    case PermissionModeEnum.BACK:
      // 从后端获取动态路由
      routeList = (await menuRouteApi()) as AppRouteRecordRaw[];
      break;
  }
  
  return routes;
}

菜单权限控制

菜单权限通过路由元数据(meta)进行配置,支持多种控制选项:

interface RouteMeta {
  title: string;                    // 菜单标题
  ignoreAuth?: boolean;             // 是否忽略权限
  roles?: RoleEnum[];               // 允许的角色
  hideMenu?: boolean;               // 是否隐藏菜单
  icon?: string;                    // 菜单图标
  orderNo?: number;                 // 排序号
}

按钮权限精细化控制

JeeSite提供了v-auth指令来实现按钮级别的权限控制:

<template>
  <a-button type="primary" @click="handleForm" v-auth="'sys:menu:edit'">
    <Icon icon="i-fluent:add-12-filled" /> 新增菜单
  </a-button>
  
  <a-button danger @click="handleDelete" v-auth="'sys:menu:delete'">
    <Icon icon="i-ant-design:delete-outlined" /> 删除
  </a-button>
</template>

权限指令的核心实现:

function isAuth(el: Element, binding: any) {
  const { hasPermission } = usePermission();
  const value = binding.value;
  if (!value) return;
  if (!hasPermission(value)) {
    el.parentNode?.removeChild(el);  // 无权限时移除元素
  }
}

权限验证逻辑

权限验证采用灵活的匹配算法,支持通配符和精确匹配:

function hasPermission(value?: string | string[]): boolean {
  const permMode = projectSetting.permissionMode;
  
  if (PermissionModeEnum.BACK === permMode) {
    const permiCodeList = permissionStore.getPermCodeList;
    
    if (value) {
      const values = !isArray(value) ? [value] : value;
      for (const val of values) {
        if (val && val !== '') {
          const currPermi = val.split(':');
          for (const permi of permiCodeList) {
            if (isPermitted(permi, currPermi)) {
              return true;  // 权限匹配成功
            }
          }
        }
      }
    }
    return false;
  }
  return true;
}

表格操作权限控制

在数据表格中,可以通过auth属性控制每行操作的权限:

const actionColumn: BasicColumn = {
  width: 180,
  actions: (record: Recordable) => [
    {
      icon: 'i-clarity:note-edit-line',
      title: '编辑菜单',
      onClick: handleEdit,
      auth: 'sys:menu:edit',  // 权限控制
    },
    {
      icon: 'i-ant-design:delete-outlined',
      title: '删除菜单',
      onClick: handleDelete,
      auth: 'sys:menu:delete',
    }
  ]
};

权限配置管理

系统提供可视化的权限配置界面,支持菜单和按钮权限的统一管理:

配置项 说明 示例
菜单类型 区分菜单和权限节点 1-菜单, 2-权限
权限标识 权限的唯一标识符 sys:menu:edit
可见性 控制菜单是否显示 是/否
状态 启用或禁用 0-正常, 2-停用

权限缓存与更新

为了保证权限数据的一致性,系统实现了权限缓存和动态更新机制:

async function resume() {
  const tabStore = useMultipleTabStore();
  tabStore.clearCacheTabs();
  resetRouter();  // 重置路由
  
  // 重新构建路由和权限
  const routes = await permissionStore.buildRoutesAction();
  routes.forEach((route) => {
    router.addRoute(route as unknown as RouteRecordRaw);
  });
  
  permissionStore.setLastBuildMenuTime();
  closeAll();  // 关闭所有标签页
}

最佳实践建议

  1. 权限命名规范:遵循模块:功能:操作的命名约定,保持权限标识的一致性
  2. 最小权限原则:为每个操作分配最小必要的权限,避免过度授权
  3. 定期审计:定期检查和清理未使用的权限配置
  4. 测试验证:编写权限相关的单元测试,确保权限控制的正确性
  5. 日志记录:记录重要的权限操作,便于安全审计和问题排查

通过这套完善的权限控制体系,JeeSite为企业级应用提供了安全可靠的菜单和按钮权限管理解决方案,既保证了系统的安全性,又提供了良好的开发体验。

路由守卫与身份认证的安全机制

JeeSite Vue3 前端框架采用了先进的路由守卫机制和身份认证体系,为企业级应用提供了坚实的安全保障。该机制基于 Vue Router 的导航守卫功能,结合 Pinia 状态管理,实现了完整的权限控制和用户身份验证流程。

路由守卫架构设计

JeeSite 的路由守卫系统采用分层设计,通过多个守卫协同工作,确保路由跳转的安全性和完整性:

flowchart TD
    A[路由导航开始] --> B[权限守卫<br>permissionGuard]
    B --> C{白名单检查}
    C -->|是| D[直接放行]
    C -->|否| E{Token验证}
    E -->|无效| F[重定向到登录页]
    E -->|有效| G[获取用户信息]
    G --> H[参数菜单守卫<br>paramMenuGuard]
    H --> I[状态守卫<br>stateGuard]
    I --> J[页面状态管理]
    J --> K[路由跳转完成]

核心守卫实现

1. 权限守卫 (Permission Guard)

权限守卫是系统的第一道防线,负责处理用户身份验证和路由权限控制:

// packages/core/router/guard/permissionGuard.ts
export function createPermissionGuard(router: Router) {
  const userStore = useUserStoreWithOut();
  const permissionStore = usePermissionStoreWithOut();
  
  router.beforeEach(async (to, from, next) => {
    // 白名单路由直接放行
    const whitePathList: PageEnum[] = [LOGIN_PATH, MOD_PWD_PAGE];
    if (whitePathList.includes(to.path as PageEnum)) {
      next();
      return;
    }

    // Token验证
    const token = !userStore.getSessionTimeout;
    if (!token) {
      if (to.meta.ignoreAuth) {
        next();
        return;
      }
      // 重定向到登录页
      next({
        path: LOGIN_PATH,
        replace: true,
        query: { redirect: to.path }
      });
      return;
    }

    // 动态路由构建
    if (!permissionStore.getIsDynamicAddedRoute) {
      const routes = await permissionStore.buildRoutesAction();
      routes.forEach((route) => {
        router.addRoute(route as unknown as RouteRecordRaw);
      });
      permissionStore.setDynamicAddedRoute(true);
    }
    
    next();
  });
}

2. 参数菜单守卫 (Param Menu Guard)

参数菜单守卫负责处理动态路由参数,确保菜单参数的正确传递:

// packages/core/router/guard/paramMenuGuard.ts
export function createParamMenuGuard(router: Router) {
  const permissionStore = usePermissionStoreWithOut();
  
  router.beforeEach(async (to, _, next) => {
    if (!to.name || !permissionStore.getIsDynamicAddedRoute) {
      next();
      return;
    }

    // 配置动态参数菜单
    let menus: Menu[] = [];
    if (isBackMode()) {
      menus = permissionStore.getBackMenuList;
    } else if (isRouteMappingMode()) {
      menus = permissionStore.getFrontMenuList;
    }
    menus.forEach((item) => configureDynamicParamsMenu(item, to.params));
    
    next();
  });
}

3. 状态守卫 (State Guard)

状态守卫负责页面状态的管理和恢复,确保用户操作的连续性:

// packages/core/router/guard/stateGuard.ts
export function createStateGuard(router: Router) {
  router.afterEach((to) => {
    // 页面状态管理逻辑
    if (to.meta?.keepAlive) {
      // 保存页面状态
    }
  });
}

身份认证机制

JeeSite 的身份认证系统基于 Token 机制,结合本地存储和状态管理:

用户状态管理

// packages/core/store/modules/user.ts
export const useUserStore = defineStore('app-user', {
  state: (): UserState => ({
    userInfo: null,
    token: undefined,
    roleList: [],
    sessionTimeout: undefined,
    lastUpdateTime: 0,
    pageCache: {},
    emitter: mitt(),
  }),
  
  getters: {
    getUserInfo(): UserInfo {
      return this.userInfo || getAuthCache<UserInfo>(USER_INFO_KEY) || {};
    },
    getToken(): string {
      return this.token || getAuthCache<string>(TOKEN_KEY);
    }
  },
  
  actions: {
    async login(params: LoginParams) {
      const res = await loginApi(params);
      if (res.result !== 'true') {
        return res;
      }
      await this.afterLoginAction(res, true);
      return res;
    },
    
    async afterLoginAction(res: LoginResult, goHome?: boolean) {
      this.setUserInfo(res);
      this.setSessionTimeout(false);
      
      // 动态添加路由
      const permissionStore = usePermissionStore();
      if (!permissionStore.isDynamicAddedRoute) {
        const routes = await permissionStore.buildRoutesAction();
        routes.forEach((route) => {
          router.addRoute(route as unknown as RouteRecordRaw);
        });
        permissionStore.setDynamicAddedRoute(true);
      }
      
      if (goHome) {
        await router.replace(res.user?.homePath || PageEnum.BASE_HOME);
      }
    }
  }
});

安全特性表格

安全特性 实现方式 作用描述
Token 验证 JWT Token + 本地存储 用户身份认证和会话管理
路由白名单 预定义白名单路径 允许无需认证的页面访问
动态路由 后端返回 + 前端动态添加 按用户权限生成可访问路由
会话超时 时间戳检测 + 自动登出 防止会话被长期占用
密码策略 强制修改密码提示 增强账户安全性
权限控制 路由元信息 + 按钮权限 细粒度的访问控制

认证流程时序图

sequenceDiagram
    participant U as 用户
    participant R as 路由守卫
    participant US as 用户存储
    participant PS as 权限存储
    participant API as 后端API

    U->>R: 访问受保护路由
    R->>US: 检查Token有效性
    US-->>R: Token状态
    alt Token无效
        R->>U: 重定向到登录页
    else Token有效
        R->>US: 获取用户信息
        US->>API: 请求用户数据
        API-->>US: 返回用户信息
        US-->>R: 用户信息
        R->>PS: 检查动态路由
        alt 需要构建路由
            PS->>API: 请求权限路由
            API-->>PS: 返回路由配置
            PS->>R: 动态添加路由
        end
        R->>U: 允许访问目标页面
    end

错误处理与恢复机制

系统提供了完善的错误处理机制,确保在认证失败或网络异常时的用户体验:

// 异常处理示例
try {
  await userStore.getUserInfoAction();
} catch (error: any) {
  let path = LOGIN_PATH as string;
  if (to.path !== '/' && to.path !== LOGIN_PATH) {
    path = path + '?redirect=' + to.fullPath;
  }
  next(path);
  return;
}

缓存策略

JeeSite 采用多层缓存策略来优化认证性能:

缓存层级 存储介质 生命周期 用途
内存缓存 Pinia Store 页面会话期间 快速访问用户状态
本地存储 localStorage 长期持久化 Token和用户信息持久化
会话缓存 sessionStorage 浏览器会话期间 临时状态管理

这种路由守卫与身份认证的安全机制为 JeeSite 企业级应用提供了坚实的安全基础,确保了系统的可靠性和用户数据的安全性。

多租户与数据隔离的技术实现方案

在企业级应用开发中,多租户架构是实现SaaS(软件即服务)模式的核心技术。JeeSite通过精心设计的多层次数据隔离方案,为企业提供了安全、高效的多租户支持。本节将深入探讨JeeSite在多租户架构和数据隔离方面的技术实现。

多租户架构设计理念

JeeSite采用基于公司(Corporation)的多租户模型,每个租户对应一个独立的企业实体。这种设计允许不同企业在同一套系统中完全隔离地运行,同时共享底层基础设施。

classDiagram
    class Tenant {
        +String tenantCode
        +String tenantName
        +Boolean enabled
        +Date createTime
    }
    
    class User {
        +String userId
        +String tenantCode
        +String username
        +String password
    }
    
    class Data {
        +String dataId
        +String tenantCode
        +Object content
    }
    
    class Permission {
        +String permId
        +String tenantCode
        +String resource
    }
    
    Tenant "1" -- "*" User : 拥有
    Tenant "1" -- "*" Data : 包含
    Tenant "1" -- "*" Permission : 配置

数据隔离技术实现

1. 数据库层面的隔离策略

JeeSite支持多种数据库隔离方案,根据不同的业务场景和安全要求灵活选择:

隔离级别 实现方式 优点 缺点 适用场景
独立数据库 每个租户独立的数据库实例 完全隔离,安全性最高 成本高,维护复杂 金融、政府等高安全要求场景
共享数据库独立Schema 同一数据库实例,不同Schema 较好的隔离性,成本适中 需要数据库权限管理 中型企业应用
共享Schema数据标记 同一Schema,通过tenant_id字段区分 成本最低,扩展性好 需要严格的代码控制 小型企业或初创公司

2. 租户标识的传递与识别

JeeSite通过统一的租户上下文管理机制,确保在每个请求中正确识别和处理租户信息:

// 租户上下文管理
class TenantContext {
  private static readonly context = new AsyncLocalStorage<string>();
  
  static setTenant(tenantCode: string) {
    this.context.enterWith(tenantCode);
  }
  
  static getCurrentTenant(): string {
    return this.context.getStore() || 'default';
  }
  
  static runWithTenant<T>(tenantCode: string, callback: () => T): T {
    return this.context.run(tenantCode, callback);
  }
}

// 在API拦截器中自动设置租户上下文
const tenantInterceptor = {
  request: (config: AxiosRequestConfig) => {
    const tenantCode = getTenantFromRequest(config);
    if (tenantCode) {
      TenantContext.setTenant(tenantCode);
      config.headers['X-Tenant-Code'] = tenantCode;
    }
    return config;
  }
};

3. 数据访问层的租户过滤

在数据持久化层,JeeSite通过AOP(面向切面编程)技术自动为所有数据库操作添加租户过滤条件:

// 数据访问拦截器
@Entity
@Table(name = "business_data")
@TenantAware // 租户感知注解
class BusinessData {
  @Id
  @GeneratedValue
  id: number;
  
  @Column
  dataContent: string;
  
  @Column
  @TenantId // 租户标识字段
  tenantCode: string;
}

// AOP拦截器实现
@Aspect
class TenantDataFilterAspect {
  @Around("@annotation(org.springframework.stereotype.Repository)")
  Object filterByTenant(ProceedingJoinPoint joinPoint) {
    String tenantCode = TenantContext.getCurrentTenant();
    if (tenantCode != null) {
      // 自动添加租户过滤条件
      Criteria criteria = // 获取当前查询条件
      criteria.add(Restrictions.eq("tenantCode", tenantCode));
    }
    return joinPoint.proceed();
  }
}

权限系统的多租户支持

1. 角色与权限的租户隔离

JeeSite的权限系统天然支持多租户,每个租户拥有独立的角色和权限体系:

flowchart TD
    A[用户请求] --> B{租户识别}
    B -->|成功| C[加载租户权限配置]
    B -->|失败| D[返回无权限错误]
    C --> E[验证用户角色权限]
    E -->|有权限| F[执行操作]
    E -->|无权限| D

2. 跨租户数据访问控制

对于需要跨租户访问的特殊场景,JeeSite提供了严格的安全控制机制:

// 跨租户访问服务
class CrossTenantAccessService {
  
  @PreAuthorize("hasRole('SUPER_ADMIN')")
  async accessCrossTenantData(tenantCode: string, dataId: string) {
    // 超级管理员可以跨租户访问数据
    return TenantContext.runWithTenant(tenantCode, () => {
      return dataRepository.findById(dataId);
    });
  }
  
  @PreAuthorize("hasPermission(#sourceTenant, 'READ') and hasPermission(#targetTenant, 'READ')")
  async shareDataBetweenTenants(sourceTenant: string, targetTenant: string, dataId: string) {
    // 需要同时拥有源租户和目标租户的读取权限
    const data = await TenantContext.runWithTenant(sourceTenant, () => {
      return dataRepository.findById(dataId);
    });
    
    return TenantContext.runWithTenant(targetTenant, () => {
      return dataRepository.save(data);
    });
  }
}

性能优化与缓存策略

在多租户环境下,缓存管理需要特别考虑租户隔离:

1. 租户感知的缓存机制

// 租户级别的缓存管理
class TenantAwareCacheManager {
  private cache: Map<string, Cache> = new Map();
  
  getCache(tenantCode: string): Cache {
    if (!this.cache.has(tenantCode)) {
      this.cache.set(tenantCode, new LRUCache(1000));
    }
    return this.cache.get(tenantCode)!;
  }
  
  get<T>(tenantCode: string, key: string): T | null {
    return this.getCache(tenantCode).get(key);
  }
  
  set<T>(tenantCode: string, key: string, value: T, ttl?: number) {
    this.getCache(tenantCode).set(key, value, ttl);
  }
}

// 使用示例
const userCache = new TenantAwareCacheManager();
const userData = userCache.get(currentTenant, `user:${userId}`);

2. 数据库连接池优化

对于共享数据库模式,JeeSite采用智能连接池管理:

class TenantAwareConnectionPool {
  private pools: Map<string, ConnectionPool> = new Map();
  private defaultPool: ConnectionPool;
  
  getConnection(tenantCode?: string): Connection {
    const pool = tenantCode ? this.pools.get(tenantCode) : this.defaultPool;
    return pool!.getConnection();
  }
  
  // 根据租户活跃度动态调整连接池大小
  adjustPoolSizes() {
    this.pools.forEach((pool, tenantCode) => {
      const usage = this.getTenantUsage(tenantCode);
      pool.setMaxConnections(usage * 2 + 10); // 根据使用情况动态调整
    });
  }
}

安全审计与合规性

多租户环境下的安全审计至关重要,JeeSite提供了完整的审计追踪功能:

// 审计日志记录
class TenantAuditService {
  @Async
  async logAuditEvent(event: AuditEvent) {
    const tenantCode = TenantContext.getCurrentTenant();
    const auditLog = {
      tenantCode,
      eventType: event.type,
      userId: event.userId,
      timestamp: new Date(),
      details: event.details,
      ipAddress: event.ipAddress
    };
    
    // 存储到租户特定的审计日志表
    await auditRepository.save(auditLog);
  }
}

// 数据变更追踪
@Entity
@Table(name = "data_versions")
class DataVersion {
  @Id
  @GeneratedValue
  id: number;
  
  @Column
  tenantCode: string;
  
  @Column
  dataId: string;
  
  @Column
  operation: string; // CREATE, UPDATE, DELETE
  
  @Column
  oldValue: string;
  
  @Column  
  newValue: string;
  
  @Column
  operator: string;
  
  @Column
  operateTime: Date;
}

灾难恢复与数据迁移

多租户架构下的数据备份和恢复策略:

flowchart LR
    A[生产环境] --> B[定期全量备份]
    A --> C[实时增量备份]
    B --> D[租户A备份数据]
    B --> E[租户B备份数据]
    C --> F[租户A增量日志]
    C --> G[租户B增量日志]
    D --> H[灾难恢复系统]
    E --> H
    F --> H
    G --> H

JeeSite的多租户架构通过多层次、细粒度的数据隔离方案,为企业提供了安全可靠的多租户支持。从数据库层面的物理隔离到应用层的逻辑隔离,从权限控制到审计追踪,每一个环节都经过精心设计和严格测试,确保不同租户之间的数据完全隔离,同时保持系统的性能和可扩展性。

这种架构不仅满足了企业级应用的安全要求,还为系统的横向扩展和业务增长提供了坚实的技术基础。无论是小型创业公司还是大型企业集团,都可以基于JeeSite的多租户架构构建安全、稳定、可扩展的企业级应用系统。

JeeSite通过完善的动态路由和权限管理体系,为企业级应用提供了坚实的安全基础。系统采用基于Vue Router 4.x的动态路由架构,结合精细化的权限控制策略,实现了从路由级别到按钮级别的全方位安全管控。多租户架构支持通过数据库隔离、Schema分离和数据标记等多种方式实现数据隔离,确保不同租户间的完全隔离。权限系统通过统一的权限模型和灵活的配置方式,提供了前后端一致的权限验证机制。性能优化方面采用了路由懒加载、缓存策略和代码分割等技术,确保系统的高效运行。这套解决方案不仅满足了企业级应用的安全要求,还为系统的横向扩展和业务增长提供了可靠的技术基础,是构建安全、稳定、可扩展的企业级应用系统的理想选择。

登录后查看全文
热门项目推荐
相关项目推荐