JeeSite路由与权限管理:构建安全的企业级应用架构
本文详细介绍了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采用了多项优化措施:
- 路由懒加载:所有路由组件均采用动态导入
- 路由缓存:已添加的路由状态进行缓存,避免重复构建
- 代码分割:基于模块的路由分组,优化打包体积
- 预加载策略:关键路由组件进行预加载
// 路由预加载策略
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(); // 关闭所有标签页
}
最佳实践建议
- 权限命名规范:遵循
模块:功能:操作的命名约定,保持权限标识的一致性 - 最小权限原则:为每个操作分配最小必要的权限,避免过度授权
- 定期审计:定期检查和清理未使用的权限配置
- 测试验证:编写权限相关的单元测试,确保权限控制的正确性
- 日志记录:记录重要的权限操作,便于安全审计和问题排查
通过这套完善的权限控制体系,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分离和数据标记等多种方式实现数据隔离,确保不同租户间的完全隔离。权限系统通过统一的权限模型和灵活的配置方式,提供了前后端一致的权限验证机制。性能优化方面采用了路由懒加载、缓存策略和代码分割等技术,确保系统的高效运行。这套解决方案不仅满足了企业级应用的安全要求,还为系统的横向扩展和业务增长提供了可靠的技术基础,是构建安全、稳定、可扩展的企业级应用系统的理想选择。
Kimi-K2.5Kimi K2.5 是一款开源的原生多模态智能体模型,它在 Kimi-K2-Base 的基础上,通过对约 15 万亿混合视觉和文本 tokens 进行持续预训练构建而成。该模型将视觉与语言理解、高级智能体能力、即时模式与思考模式,以及对话式与智能体范式无缝融合。Python00
GLM-4.7-FlashGLM-4.7-Flash 是一款 30B-A3B MoE 模型。作为 30B 级别中的佼佼者,GLM-4.7-Flash 为追求性能与效率平衡的轻量化部署提供了全新选择。Jinja00
VLOOKVLOOK™ 是优雅好用的 Typora/Markdown 主题包和增强插件。 VLOOK™ is an elegant and practical THEME PACKAGE × ENHANCEMENT PLUGIN for Typora/Markdown.Less00
PaddleOCR-VL-1.5PaddleOCR-VL-1.5 是 PaddleOCR-VL 的新一代进阶模型,在 OmniDocBench v1.5 上实现了 94.5% 的全新 state-of-the-art 准确率。 为了严格评估模型在真实物理畸变下的鲁棒性——包括扫描伪影、倾斜、扭曲、屏幕拍摄和光照变化——我们提出了 Real5-OmniDocBench 基准测试集。实验结果表明,该增强模型在新构建的基准测试集上达到了 SOTA 性能。此外,我们通过整合印章识别和文本检测识别(text spotting)任务扩展了模型的能力,同时保持 0.9B 的超紧凑 VLM 规模,具备高效率特性。Python00
KuiklyUI基于KMP技术的高性能、全平台开发框架,具备统一代码库、极致易用性和动态灵活性。 Provide a high-performance, full-platform development framework with unified codebase, ultimate ease of use, and dynamic flexibility. 注意:本仓库为Github仓库镜像,PR或Issue请移步至Github发起,感谢支持!Kotlin07
compass-metrics-modelMetrics model project for the OSS CompassPython00