130 lines
7.1 KiB
SQL
130 lines
7.1 KiB
SQL
-- =============================================================================
|
||
-- SIP 认证(apt_sip_auth)
|
||
-- 定位:分机在 Asterisk 上的 auth 账号,与 endpoint 1:1(可先建认证后绑分机)。
|
||
-- 多租户/多实例:
|
||
-- * 唯一性 = (gyid, instance_code, username) —— 同一实例下用户名唯一;
|
||
-- 不同公寓或不同 Asterisk 实例可出现同名用户名,但彼此不可见;
|
||
-- * 所有读写必须同时带 gyid + instance_code,禁止只按 username 查(跨公寓串号);
|
||
-- * auth_id 采用 AUTH-<instance_code>-<username>,在实例内全局唯一,供 ps_auths.id 使用。
|
||
-- 口令策略:
|
||
-- * secret_mode='PLAIN':库内口令,默认 psw.voip(内网/联调用);
|
||
-- * secret_mode='ENV' :只存环境变量名 secret_ref,取值在渲染/同步时注入,
|
||
-- 生产建议用这一档(与 APT_AMI_SECRET 同一原则,不把口令写进库与日志);
|
||
-- * 两种模式都保留 secret_version / last_rotated_at,便于轮换与审计。
|
||
-- 幂等:建表 IF NOT EXISTS;种子与视图可重复执行。
|
||
-- =============================================================================
|
||
SET NAMES utf8mb4;
|
||
|
||
CREATE TABLE IF NOT EXISTS apt_sip_auth (
|
||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||
gyid VARCHAR(32) NOT NULL COMMENT '公寓标识(租户隔离键)',
|
||
instance_code VARCHAR(64) NOT NULL COMMENT 'Asterisk 实例(apt_ast_instance.instance_code)',
|
||
username VARCHAR(64) NOT NULL COMMENT 'SIP 用户名/分机号',
|
||
auth_id VARCHAR(128) NOT NULL COMMENT 'Asterisk ps_auths.id,约定 AUTH-<instance>-<username>',
|
||
endpoint_id VARCHAR(64) NULL COMMENT '关联分机(1:1,可空以便先建认证后绑分机)',
|
||
auth_type VARCHAR(20) NOT NULL DEFAULT 'userpass' COMMENT 'Asterisk auth_type',
|
||
secret_mode VARCHAR(10) NOT NULL DEFAULT 'PLAIN' COMMENT 'PLAIN=库内口令 / ENV=环境变量',
|
||
secret_plain VARCHAR(128) NOT NULL DEFAULT 'psw.voip' COMMENT 'secret_mode=PLAIN 时的口令;空串表示未设置',
|
||
secret_ref VARCHAR(64) NULL COMMENT 'secret_mode=ENV 时的环境变量名',
|
||
secret_version INT NOT NULL DEFAULT 1 COMMENT '口令版本,轮换时 +1',
|
||
realm VARCHAR(64) NOT NULL DEFAULT 'asterisk' COMMENT 'Asterisk auth realm',
|
||
state VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' COMMENT 'ACTIVE/DISABLED/ROTATING',
|
||
enabled TINYINT NOT NULL DEFAULT 1,
|
||
last_rotated_at DATETIME(3) NULL,
|
||
sync_state VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/SYNCED/FAILED/DRIFT',
|
||
config_version BIGINT NOT NULL DEFAULT 1,
|
||
deleted TINYINT NOT NULL DEFAULT 0,
|
||
create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||
update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||
PRIMARY KEY (id),
|
||
UNIQUE KEY uk_sipauth_gyid_auth_id (gyid, auth_id),
|
||
UNIQUE KEY uk_sipauth_instance_username (gyid, instance_code, username),
|
||
UNIQUE KEY uk_sipauth_instance_endpoint (gyid, instance_code, endpoint_id),
|
||
KEY idx_sipauth_gyid_state (gyid, instance_code, state, enabled),
|
||
KEY idx_sipauth_gyid_endpoint (gyid, endpoint_id),
|
||
CONSTRAINT ck_sipauth_secret_mode CHECK (secret_mode IN ('PLAIN','ENV')),
|
||
CONSTRAINT ck_sipauth_state CHECK (state IN ('ACTIVE','DISABLED','ROTATING')),
|
||
CONSTRAINT ck_sipauth_auth_type CHECK (auth_type IN ('userpass','md5','userpass,md5')),
|
||
CONSTRAINT ck_sipauth_secret_ref CHECK (secret_mode = 'PLAIN' OR secret_ref IS NOT NULL)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
|
||
COMMENT='SIP 认证账号(按公寓 + Asterisk 实例隔离;默认口令 psw.voip 仅限内网/联调)';
|
||
|
||
-- -----------------------------------------------------------------------------
|
||
-- 种子:为已登记分机补认证账号(每个公寓取第一个启用的实例;已存在则跳过)
|
||
-- -----------------------------------------------------------------------------
|
||
INSERT INTO apt_sip_auth
|
||
(gyid, instance_code, username, auth_id, endpoint_id, secret_plain)
|
||
SELECT e.gyid,
|
||
i.instance_code,
|
||
e.extension,
|
||
CONCAT('AUTH-', i.instance_code, '-', e.extension),
|
||
e.endpoint_id,
|
||
'psw.voip'
|
||
FROM apt_sip_endpoint e
|
||
JOIN apt_ast_instance i
|
||
ON i.id = (SELECT i2.id FROM apt_ast_instance i2
|
||
WHERE i2.gyid = e.gyid AND i2.deleted = 0 AND i2.enabled = 1
|
||
ORDER BY i2.id LIMIT 1)
|
||
LEFT JOIN apt_sip_auth a
|
||
ON a.gyid = e.gyid AND a.instance_code = i.instance_code AND a.username = e.extension
|
||
WHERE e.deleted = 0
|
||
AND a.id IS NULL;
|
||
|
||
-- -----------------------------------------------------------------------------
|
||
-- Asterisk realtime 视图:ps_auths / ps_endpoints(多实例按 gyid + instance_code 过滤)
|
||
-- ENV 模式在视图中不回显口令(password 为 NULL),由同步器渲染后再下发。
|
||
-- -----------------------------------------------------------------------------
|
||
CREATE OR REPLACE VIEW ps_auths AS
|
||
SELECT auth_id AS id,
|
||
auth_type,
|
||
username,
|
||
CASE WHEN secret_mode = 'PLAIN' THEN secret_plain END AS password,
|
||
realm
|
||
FROM apt_sip_auth
|
||
WHERE deleted = 0 AND enabled = 1 AND state = 'ACTIVE';
|
||
|
||
CREATE OR REPLACE VIEW ps_endpoints AS
|
||
SELECT e.endpoint_id AS id,
|
||
'transport-udp' AS transport,
|
||
a.aor_id AS aors,
|
||
au.auth_id AS auth,
|
||
'from-internal' AS context,
|
||
'ulaw' AS allow,
|
||
'all' AS disallow,
|
||
'no' AS direct_media,
|
||
e.extension AS callerid,
|
||
'yes' AS rewrite_contact
|
||
FROM apt_sip_endpoint e
|
||
JOIN apt_sip_aor a
|
||
ON a.gyid = e.gyid AND a.endpoint_id = e.endpoint_id AND a.deleted = 0
|
||
LEFT JOIN apt_sip_auth au
|
||
ON au.gyid = e.gyid AND au.endpoint_id = e.endpoint_id
|
||
AND au.deleted = 0 AND au.enabled = 1 AND au.state = 'ACTIVE'
|
||
WHERE e.deleted = 0 AND e.enabled = 1;
|
||
|
||
-- -----------------------------------------------------------------------------
|
||
-- 校验
|
||
-- -----------------------------------------------------------------------------
|
||
SELECT '=== 36. apt_sip_auth 列数(应 20)===' AS section;
|
||
SELECT COUNT(*) AS auth_columns
|
||
FROM information_schema.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_sip_auth';
|
||
|
||
SELECT '=== 37. 唯一键(应 3:auth_id / instance+username / instance+endpoint)===' AS section;
|
||
SELECT INDEX_NAME, GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) AS cols
|
||
FROM information_schema.STATISTICS
|
||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_sip_auth' AND NON_UNIQUE = 0
|
||
GROUP BY INDEX_NAME;
|
||
|
||
SELECT '=== 38. 默认口令 ===' AS section;
|
||
SELECT COLUMN_NAME, COLUMN_DEFAULT
|
||
FROM information_schema.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_sip_auth'
|
||
AND COLUMN_NAME IN ('secret_plain','secret_mode');
|
||
|
||
SELECT '=== 39. 现有认证账号(按实例分布)===' AS section;
|
||
SELECT gyid, instance_code, COUNT(*) AS accounts, SUM(secret_mode = 'PLAIN') AS plain_accounts
|
||
FROM apt_sip_auth
|
||
WHERE deleted = 0
|
||
GROUP BY gyid, instance_code;
|