wvp-GB28181-pro多租户支持:数据隔离与权限控制实现
【免费下载链接】wvp-GB28181-pro 项目地址: https://gitcode.com/GitHub_Trending/wv/wvp-GB28181-pro
一、多租户架构设计背景与挑战
在安防监控系统中,多租户(Multi-Tenancy)架构要求系统能为不同组织或用户组(租户)提供独立的数据空间和资源访问边界。传统监控平台常面临以下痛点:
- 数据混杂:不同租户设备、录像文件存储在同一数据库表中,缺乏隔离机制
- 权限越界:操作员可能访问其他租户的敏感视频流
- 资源争抢:多租户并发访问时的系统资源分配问题
wvp-GB28181-pro作为GB/T 28181标准的开源实现,通过角色访问控制(RBAC)与数据过滤机制,构建了轻量级多租户支持方案。本文将从数据隔离、权限控制、实现原理三个维度,详解如何基于现有架构实现租户级资源隔离。
二、数据隔离实现机制
2.1 数据库层隔离设计
系统采用共享数据库-独立Schema模式,通过以下表结构设计实现基础隔离:
| 核心表名 | 关键隔离字段 | 说明 |
|---|---|---|
| wvp_user | role_id | 用户与角色关联 |
| wvp_user_role | user_id, role_id | 用户-角色多对多映射 |
| wvp_device | region_id | 设备按区域划分(模拟租户) |
| wvp_stream | gb_device_id | 流与设备强关联 |
SQL示例:设备表区域隔离
-- 初始化设备表时加入区域ID字段(模拟租户ID)
CREATE TABLE wvp_device (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
device_id VARCHAR(64) NOT NULL,
name VARCHAR(128),
region_id INT NOT NULL COMMENT '区域ID(租户隔离标识)',
status TINYINT DEFAULT 0,
CONSTRAINT uk_device_id UNIQUE (device_id)
);
2.2 应用层数据过滤
在业务逻辑层,通过ThreadLocal存储当前操作用户上下文,实现数据访问时的动态过滤:
// 设备服务实现类中的租户过滤逻辑
@Service
public class DeviceServiceImpl implements IDeviceService {
@Autowired
private DeviceMapper deviceMapper;
@Override
public List<Device> getDeviceList(DeviceQuery query) {
// 获取当前用户所属区域ID(模拟租户ID)
LoginUser currentUser = SecurityUtils.getCurrentUser();
Integer tenantRegionId = currentUser.getRole().getRegionId();
// 动态添加租户过滤条件
query.setRegionId(tenantRegionId);
return deviceMapper.selectByQuery(query);
}
}
2.3 媒体资源隔离
通过媒体服务器(ZLMediakit)的应用名(app)和流名(stream)实现租户隔离:
- 租户A:
rtmp://server/live/tenantA_camera1 - 租户B:
rtmp://server/live/tenantB_camera1
流推送时的租户标识注入:
// StreamPushService.java
public void startPush(StreamPushParam param) {
LoginUser user = SecurityUtils.getCurrentUser();
// 生成带租户标识的流名
String tenantStream = String.format("%s_%s", user.getTenantCode(), param.getStream());
param.setStream(tenantStream);
zlmClient.startPushStream(param);
}
三、RBAC权限控制体系
3.1 权限模型设计
系统实现三级权限控制:
3.2 核心权限控制代码
在控制器层通过注解实现权限拦截:
@RestController
@RequestMapping("/api/device")
public class DeviceController {
@Autowired
private IDeviceService deviceService;
@GetMapping("/list")
@PreAuthorize("hasPermission('device:view')") // 权限检查
public Result<List<Device>> getDeviceList(DeviceQuery query) {
return Result.ok(deviceService.getDeviceList(query));
}
@PostMapping("/delete")
@PreAuthorize("hasPermission('device:delete')")
public Result<Void> deleteDevice(@RequestParam String deviceId) {
// 数据权限二次校验
LoginUser user = SecurityUtils.getCurrentUser();
if (!deviceService.checkTenantPermission(deviceId, user.getRole().getRegionId())) {
return Result.error("无权限操作其他租户设备");
}
deviceService.delete(deviceId);
return Result.ok();
}
}
3.3 角色配置示例
系统预置三类基础角色:
| 角色ID | 角色名称 | 权限范围 | 适用场景 |
|---|---|---|---|
| 1 | 超级管理员 | 所有功能 | 系统维护 |
| 2 | 租户管理员 | 租户内所有资源管理 | 租户运维 |
| 3 | 操作员 | 仅查看和操作授权设备 | 普通监控人员 |
角色创建SQL:
INSERT INTO wvp_role (id, name, region_id, create_time) VALUES
(2, '租户管理员', 1001, NOW()), -- 租户A管理员(region_id=1001)
(2, '租户管理员', 1002, NOW()); -- 租户B管理员(region_id=1002)
四、多租户部署与配置实践
4.1 环境准备
# 克隆代码仓库
git clone https://gitcode.com/GitHub_Trending/wv/wvp-GB28181-pro.git
cd wvp-GB28181-pro
# 初始化数据库(使用带区域字段的SQL脚本)
mysql -uroot -p < 数据库/2.7.4/初始化-mysql-2.7.4.sql
4.2 租户隔离配置步骤
- 创建租户区域
INSERT INTO wvp_region (id, name, parent_id) VALUES
(1001, '租户A区域', 0),
(1002, '租户B区域', 0);
- 创建租户管理员
// UserController.java 中添加租户管理员创建接口
@PostMapping("/createTenantAdmin")
public Result<User> createTenantAdmin(@RequestBody TenantAdminDTO dto) {
Role tenantRole = roleService.getRoleByName("租户管理员");
tenantRole.setRegionId(dto.getRegionId());
User user = new User();
user.setUsername(dto.getUsername());
user.setPassword(PasswordUtils.encode(dto.getPassword()));
user.setRole(tenantRole);
return Result.ok(userService.add(user));
}
- 配置媒体服务器租户隔离 修改
zlm.yml配置文件:
rtmp:
enabled: true
addtion:
# 根据app名隔离租户
publish: "if ($app !~ '^tenant[0-9]+$') deny;"
4.3 数据隔离效果验证
// 测试代码:验证租户数据隔离
@Test
public void testTenantIsolation() {
// 模拟租户A管理员登录
SecurityUtils.setCurrentUser(tenantAAdmin);
List<Device> tenantADevices = deviceService.getDeviceList(new DeviceQuery());
Assert.assertEquals(10, tenantADevices.size()); // 租户A应有10台设备
// 模拟租户B管理员登录
SecurityUtils.setCurrentUser(tenantBAdmin);
List<Device> tenantBDevices = deviceService.getDeviceList(new DeviceQuery());
Assert.assertEquals(8, tenantBDevices.size()); // 租户B应有8台设备
}
五、进阶特性与性能优化
5.1 动态数据源路由
对于高级租户隔离需求,可扩展实现动态数据源路由:
public class TenantDataSourceRouter extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return SecurityUtils.getCurrentUser().getTenantId();
}
}
5.2 缓存策略优化
针对多租户场景设计二级缓存:
一级缓存:租户ID + 用户ID -> 用户权限缓存
二级缓存:租户ID + 资源类型 -> 资源列表缓存
5.3 并发控制
使用Redis实现租户级别的资源限流:
// 基于Redisson的租户限流
@Bean
public RateLimiter tenantRateLimiter() {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redisson = Redisson.create(config);
return new RateLimiter() {
@Override
public boolean tryAcquire() {
String tenantKey = "rate_limit:" + SecurityUtils.getCurrentUser().getTenantId();
RRateLimiter rateLimiter = redisson.getRateLimiter(tenantKey);
rateLimiter.trySetRate(RateType.OVERALL, 100, 1, RateIntervalUnit.SECONDS);
return rateLimiter.tryAcquire(1);
}
};
}
六、方案局限性与扩展建议
6.1 当前方案限制
- 缺乏显式租户模型,需通过区域ID间接实现
- 数据库级隔离依赖应用层过滤,存在越权风险
- 租户配置未集成到管理界面,需手动操作数据库
6.2 多租户功能扩展路线图
6.3 最佳实践建议
- 中小规模部署:采用本文介绍的区域+RBAC隔离方案
- 大规模部署:建议扩展为schema隔离模式
- 高安全需求:考虑物理隔离(独立部署实例)
七、总结
wvp-GB28181-pro通过"区域划分+RBAC权限+数据过滤"三重机制,在不引入复杂多租户框架的前提下,实现了轻量级租户隔离。该方案具有以下优势:
- 兼容性好:无需修改核心协议栈代码
- 部署简单:基于现有表结构即可扩展
- 性能损耗低:仅在数据访问层增加过滤逻辑
对于需要严格隔离的场景,建议在后续版本中实现显式租户模型,通过MyBatis-Plus的TenantLineHandler或Sharding-JDBC等框架,进一步提升多租户隔离的安全性和灵活性。
通过合理配置角色权限与区域划分,wvp-GB28181-pro可满足中小规模安防监控平台的多租户管理需求,为智慧校园、连锁商超等场景提供安全可控的视频监控解决方案。
【免费下载链接】wvp-GB28181-pro 项目地址: https://gitcode.com/GitHub_Trending/wv/wvp-GB28181-pro
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



