Files
jcgl-dev/dev/sql/apt_rev01/23_sip_auth.sql
T
2026-11-12 13:36:24 +08:00

130 lines
7.1 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =============================================================================
-- 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;