- 添加API客户端、加密存储和provision/token激活逻辑 - WebSocket改用Bearer令牌认证,移除REGISTER请求 - 设备ID改为服务端下发,支持令牌刷新和强制下线处理 - 新增deviceSecret加密存储和accessToken自动刷新 - 更新设备ID获取方式为出厂SN,添加安全存储依赖
285 lines
13 KiB
SQL
285 lines
13 KiB
SQL
-- =============================================================
|
||
-- WebRTCSignalServer 数据库建表脚本 (MySQL 8.0+)
|
||
--
|
||
-- 【请手动执行,服务端代码当前仍为内存实现,不会自动建表】
|
||
--
|
||
-- 执行方式:
|
||
-- mysql -u root -p < schema.sql
|
||
--
|
||
-- 字符集统一使用 utf8mb4 / utf8mb4_0900_ai_ci
|
||
-- 所有时间字段使用 DATETIME(3),由应用层写入 UTC 时间
|
||
-- =============================================================
|
||
|
||
CREATE DATABASE IF NOT EXISTS `webrtc_signal`
|
||
DEFAULT CHARACTER SET utf8mb4
|
||
DEFAULT COLLATE utf8mb4_0900_ai_ci;
|
||
|
||
USE `webrtc_signal`;
|
||
|
||
|
||
-- =============================================================
|
||
-- 1. 主控端用户账号
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `app_user` (
|
||
`user_id` VARCHAR(32) NOT NULL COMMENT '用户ID,格式 usr_<20位Base62>',
|
||
`username` VARCHAR(32) NOT NULL COMMENT '登录名',
|
||
`password_hash` VARCHAR(100) NOT NULL COMMENT 'BCrypt 哈希(cost=12)',
|
||
`status` VARCHAR(16) NOT NULL DEFAULT 'ACTIVE'
|
||
COMMENT '账号状态:ACTIVE/SUSPENDED/BANNED',
|
||
`status_until` DATETIME(3) NULL COMMENT '临时封禁到期时间,NULL 表示永久或未封禁',
|
||
`status_reason` VARCHAR(255) NULL COMMENT '封禁原因',
|
||
`token_version` BIGINT NOT NULL DEFAULT 1
|
||
COMMENT '凭据版本号,递增后所有已签发令牌立即失效',
|
||
`is_admin` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否管理员',
|
||
|
||
-- 双因子认证
|
||
`totp_secret` VARCHAR(64) NULL COMMENT 'TOTP 密钥(Base32),NULL 表示未启用',
|
||
`totp_enabled` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'TOTP 是否已完成绑定',
|
||
|
||
-- 防爆破
|
||
`failed_attempts` INT NOT NULL DEFAULT 0 COMMENT '连续登录失败次数',
|
||
`locked_until` DATETIME(3) NULL COMMENT '锁定截止时间',
|
||
|
||
`last_login_at` DATETIME(3) NULL,
|
||
`last_login_ip` VARCHAR(64) NULL,
|
||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
|
||
ON UPDATE CURRENT_TIMESTAMP(3),
|
||
|
||
PRIMARY KEY (`user_id`),
|
||
UNIQUE KEY `uk_username` (`username`),
|
||
KEY `idx_status` (`status`)
|
||
) ENGINE=InnoDB COMMENT='主控端用户账号';
|
||
|
||
|
||
-- =============================================================
|
||
-- 2. 密码历史(防止重复使用近期密码)
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `password_history` (
|
||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||
`user_id` VARCHAR(32) NOT NULL,
|
||
`password_hash` VARCHAR(100) NOT NULL,
|
||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_user_created` (`user_id`, `created_at` DESC),
|
||
CONSTRAINT `fk_pwdhist_user` FOREIGN KEY (`user_id`)
|
||
REFERENCES `app_user` (`user_id`) ON DELETE CASCADE
|
||
) ENGINE=InnoDB COMMENT='密码历史,建议保留最近 5 条';
|
||
|
||
|
||
-- =============================================================
|
||
-- 3. 登录会话(刷新令牌上下文)
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `login_session` (
|
||
`session_id` VARCHAR(32) NOT NULL COMMENT '会话ID,格式 ses_<20位Base62>',
|
||
`principal_id` VARCHAR(32) NOT NULL COMMENT '主体ID(user_id)',
|
||
`principal_type` VARCHAR(16) NOT NULL DEFAULT 'USER' COMMENT 'USER/DEVICE',
|
||
`refresh_token_hash` VARCHAR(64) NOT NULL COMMENT '当前刷新令牌的 SHA-256,轮转后更新',
|
||
`refresh_expires_at` DATETIME(3) NOT NULL,
|
||
`ip` VARCHAR(64) NULL,
|
||
`user_agent` VARCHAR(256) NULL,
|
||
`revoked` TINYINT(1) NOT NULL DEFAULT 0,
|
||
`revoked_reason` VARCHAR(255) NULL,
|
||
`last_seen_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
|
||
PRIMARY KEY (`session_id`),
|
||
KEY `idx_principal` (`principal_id`, `revoked`),
|
||
KEY `idx_expires` (`refresh_expires_at`)
|
||
) ENGINE=InnoDB COMMENT='登录会话,支持踢线与刷新令牌轮转';
|
||
|
||
|
||
-- =============================================================
|
||
-- 4. SN 白名单(出厂/部署时批量导入)
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `allowed_device` (
|
||
`sn` VARCHAR(64) NOT NULL COMMENT '设备序列号',
|
||
`batch` VARCHAR(64) NULL COMMENT '批次标识',
|
||
`note` VARCHAR(255) NULL,
|
||
`imported_by` VARCHAR(64) NULL,
|
||
`imported_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
|
||
PRIMARY KEY (`sn`),
|
||
KEY `idx_batch` (`batch`)
|
||
) ENGINE=InnoDB COMMENT='允许激活的 SN 白名单';
|
||
|
||
|
||
-- =============================================================
|
||
-- 5. 被控端设备
|
||
-- SN 仅作内部主键,对外一律使用高熵不可枚举的 device_uid
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `device` (
|
||
`device_uid` VARCHAR(32) NOT NULL COMMENT '对外设备ID,格式 dev_<22位Base62>',
|
||
`sn` VARCHAR(64) NOT NULL COMMENT '设备序列号(内部使用,勿对外暴露)',
|
||
`secret_hash` VARCHAR(64) NOT NULL COMMENT 'deviceSecret 的 SHA-256',
|
||
`model` VARCHAR(64) NULL,
|
||
`status` VARCHAR(16) NOT NULL DEFAULT 'ACTIVE'
|
||
COMMENT 'ACTIVE/SUSPENDED/BANNED',
|
||
`status_until` DATETIME(3) NULL,
|
||
`status_reason` VARCHAR(255) NULL,
|
||
`token_version` BIGINT NOT NULL DEFAULT 1,
|
||
|
||
-- 防骚扰配置(P1 阶段使用)
|
||
`strict_mode` TINYINT(1) NOT NULL DEFAULT 1
|
||
COMMENT '严格模式:仅允许已绑定账号连接',
|
||
`quiet_start` TIME NULL COMMENT '勿扰时段开始',
|
||
`quiet_end` TIME NULL COMMENT '勿扰时段结束',
|
||
|
||
`provisioned_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
`last_online_at` DATETIME(3) NULL,
|
||
|
||
PRIMARY KEY (`device_uid`),
|
||
UNIQUE KEY `uk_sn` (`sn`),
|
||
KEY `idx_status` (`status`)
|
||
) ENGINE=InnoDB COMMENT='被控端设备身份';
|
||
|
||
|
||
-- =============================================================
|
||
-- 6. 设备激活 nonce(防重放)
|
||
-- 建议配合定时任务清理过期记录,或改用 Redis
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `provision_nonce` (
|
||
`nonce` VARCHAR(64) NOT NULL,
|
||
`sn` VARCHAR(64) NULL,
|
||
`expires_at` DATETIME(3) NOT NULL,
|
||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
|
||
PRIMARY KEY (`nonce`),
|
||
KEY `idx_expires` (`expires_at`)
|
||
) ENGINE=InnoDB COMMENT='激活请求 nonce,用于防重放';
|
||
|
||
|
||
-- =============================================================
|
||
-- 7. 设备绑定关系(P1 阶段:主控端唯一寻址凭证)
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `device_binding` (
|
||
`binding_id` VARCHAR(36) NOT NULL COMMENT 'UUID',
|
||
`device_uid` VARCHAR(32) NOT NULL,
|
||
`user_id` VARCHAR(32) NOT NULL,
|
||
`role` VARCHAR(16) NOT NULL DEFAULT 'OPERATOR'
|
||
COMMENT 'OWNER/OPERATOR/VIEWER',
|
||
`alias` VARCHAR(64) NULL COMMENT '主控端自定义备注名',
|
||
`status` VARCHAR(16) NOT NULL DEFAULT 'ACTIVE' COMMENT 'ACTIVE/REVOKED',
|
||
`bound_by` VARCHAR(32) NULL,
|
||
`bound_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
`expire_at` DATETIME(3) NULL COMMENT '绑定过期时间,NULL 表示长期有效',
|
||
|
||
PRIMARY KEY (`binding_id`),
|
||
UNIQUE KEY `uk_device_user` (`device_uid`, `user_id`),
|
||
KEY `idx_user_status` (`user_id`, `status`),
|
||
KEY `idx_device_status` (`device_uid`, `status`)
|
||
) ENGINE=InnoDB COMMENT='设备与账号绑定关系';
|
||
|
||
|
||
-- =============================================================
|
||
-- 8. 配对码(P1 阶段:建立绑定)
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `pairing_code` (
|
||
`code_hash` VARCHAR(64) NOT NULL COMMENT '配对码的 SHA-256',
|
||
`device_uid` VARCHAR(32) NOT NULL,
|
||
`attempts` INT NOT NULL DEFAULT 0 COMMENT '错误尝试次数,超限即失效',
|
||
`used` TINYINT(1) NOT NULL DEFAULT 0,
|
||
`expires_at` DATETIME(3) NOT NULL,
|
||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
|
||
PRIMARY KEY (`code_hash`),
|
||
KEY `idx_device` (`device_uid`),
|
||
KEY `idx_expires` (`expires_at`)
|
||
) ENGINE=InnoDB COMMENT='一次性配对码';
|
||
|
||
|
||
-- =============================================================
|
||
-- 9. 被控端黑名单(P1 阶段:拉黑骚扰账号)
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `device_blacklist` (
|
||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||
`device_uid` VARCHAR(32) NOT NULL,
|
||
`blocked_user_id` VARCHAR(32) NOT NULL,
|
||
`reason` VARCHAR(255) NULL,
|
||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
|
||
PRIMARY KEY (`id`),
|
||
UNIQUE KEY `uk_device_user` (`device_uid`, `blocked_user_id`),
|
||
KEY `idx_device` (`device_uid`)
|
||
) ENGINE=InnoDB COMMENT='被控端黑名单';
|
||
|
||
|
||
-- =============================================================
|
||
-- 10. 连接会话记录(WebRTC 通话审计)
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `connection_session` (
|
||
`session_id` VARCHAR(36) NOT NULL,
|
||
`binding_id` VARCHAR(36) NULL,
|
||
`device_uid` VARCHAR(32) NOT NULL,
|
||
`user_id` VARCHAR(32) NOT NULL,
|
||
`auth_type` VARCHAR(16) NULL COMMENT 'NONE/CODE/PASSWORD',
|
||
`started_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
`ended_at` DATETIME(3) NULL,
|
||
`end_reason` VARCHAR(64) NULL,
|
||
|
||
PRIMARY KEY (`session_id`),
|
||
KEY `idx_device_started` (`device_uid`, `started_at` DESC),
|
||
KEY `idx_user_started` (`user_id`, `started_at` DESC)
|
||
) ENGINE=InnoDB COMMENT='远程控制会话记录';
|
||
|
||
|
||
-- =============================================================
|
||
-- 11. 审计日志(只追加,不修改)
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `audit_log` (
|
||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||
`actor_type` VARCHAR(16) NOT NULL COMMENT 'USER/DEVICE/ADMIN/SYSTEM',
|
||
`actor_id` VARCHAR(64) NULL,
|
||
`action` VARCHAR(64) NOT NULL
|
||
COMMENT 'LOGIN/LOGIN_FAILED/LOGOUT/REGISTER/PROVISION/BAN/UNBAN/KICK/BIND/UNBIND/BLACKLIST...',
|
||
`target_type` VARCHAR(16) NULL,
|
||
`target_id` VARCHAR(64) NULL,
|
||
`result` VARCHAR(16) NOT NULL DEFAULT 'SUCCESS' COMMENT 'SUCCESS/FAILURE',
|
||
`ip` VARCHAR(64) NULL,
|
||
`user_agent` VARCHAR(256) NULL,
|
||
`detail` VARCHAR(512) NULL COMMENT '注意:敏感信息需脱敏后再写入',
|
||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_actor` (`actor_id`, `created_at` DESC),
|
||
KEY `idx_action` (`action`, `created_at` DESC),
|
||
KEY `idx_created` (`created_at` DESC)
|
||
) ENGINE=InnoDB COMMENT='安全审计日志';
|
||
|
||
|
||
-- =============================================================
|
||
-- 12. 骚扰举报(P2 阶段风控)
|
||
-- =============================================================
|
||
CREATE TABLE IF NOT EXISTS `abuse_report` (
|
||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||
`device_uid` VARCHAR(32) NOT NULL COMMENT '举报方(被控端)',
|
||
`reported_user_id` VARCHAR(32) NOT NULL COMMENT '被举报账号',
|
||
`reason` VARCHAR(255) NULL,
|
||
`handled` TINYINT(1) NOT NULL DEFAULT 0,
|
||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_reported` (`reported_user_id`, `created_at` DESC),
|
||
KEY `idx_handled` (`handled`)
|
||
) ENGINE=InnoDB COMMENT='骚扰举报记录';
|
||
|
||
|
||
-- =============================================================
|
||
-- 清理建议(可配置为 MySQL Event 或应用层定时任务)
|
||
-- =============================================================
|
||
-- DELETE FROM provision_nonce WHERE expires_at < NOW();
|
||
-- DELETE FROM pairing_code WHERE expires_at < NOW();
|
||
-- DELETE FROM login_session WHERE refresh_expires_at < NOW() OR revoked = 1;
|
||
-- DELETE FROM audit_log WHERE created_at < DATE_SUB(NOW(), INTERVAL 180 DAY);
|
||
|
||
|
||
-- =============================================================
|
||
-- 初始管理员账号
|
||
-- =============================================================
|
||
-- 不在此处插入明文密码。请通过环境变量启动服务自动创建:
|
||
-- BOOTSTRAP_ADMIN_USERNAME=admin
|
||
-- BOOTSTRAP_ADMIN_PASSWORD=<强密码>
|
||
-- 或注册后手动提升权限:
|
||
-- UPDATE app_user SET is_admin = 1 WHERE username = 'admin';
|