117 lines
5.0 KiB
PL/PgSQL
117 lines
5.0 KiB
PL/PgSQL
BEGIN;
|
|
|
|
-- ============================================================================
|
|
-- LeAudit Platform Usage Stats / Login Audit Schema Patch
|
|
-- 目标:
|
|
-- 1. 补齐系统使用统计所需的登录事件明细表
|
|
-- 2. 为 sso_users 增加最近登录时间字段
|
|
-- 3. 为评查触发人统计补齐必要索引
|
|
-- 说明:
|
|
-- - 脚本设计为幂等,可重复执行
|
|
-- - 不依赖前端,可由 DBA 或运维先行执行
|
|
-- ============================================================================
|
|
|
|
-- --------------------------------------------------------------------------
|
|
-- 1. 用户最近登录时间
|
|
-- --------------------------------------------------------------------------
|
|
ALTER TABLE sso_users
|
|
ADD COLUMN IF NOT EXISTS last_login_at TIMESTAMPTZ NULL;
|
|
|
|
COMMENT ON COLUMN sso_users.last_login_at IS '最近一次登录成功时间,用于用户维度统计与登录态审计';
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_sso_users_last_login_at
|
|
ON sso_users(last_login_at DESC)
|
|
WHERE deleted_at IS NULL;
|
|
|
|
-- --------------------------------------------------------------------------
|
|
-- 2. 登录事件审计表
|
|
-- --------------------------------------------------------------------------
|
|
CREATE TABLE IF NOT EXISTS usage_login_events (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NULL,
|
|
sub VARCHAR(128) NULL,
|
|
username_snapshot VARCHAR(128) NULL,
|
|
nick_name_snapshot VARCHAR(128) NULL,
|
|
department_name_snapshot VARCHAR(255) NULL,
|
|
ou_id_snapshot VARCHAR(128) NULL,
|
|
ou_name_snapshot VARCHAR(255) NULL,
|
|
area_snapshot VARCHAR(64) NULL,
|
|
login_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
login_result VARCHAR(16) NOT NULL,
|
|
login_type VARCHAR(32) NOT NULL,
|
|
ip_address VARCHAR(64) NULL,
|
|
user_agent VARCHAR(1024) NULL,
|
|
client_type VARCHAR(32) NULL,
|
|
token_jti VARCHAR(128) NULL,
|
|
failure_reason VARCHAR(255) NULL,
|
|
extra JSONB NULL DEFAULT '{}'::jsonb,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
deleted_at TIMESTAMPTZ NULL,
|
|
CONSTRAINT fk_usage_login_events_user
|
|
FOREIGN KEY (user_id) REFERENCES sso_users(id) ON DELETE SET NULL,
|
|
CONSTRAINT chk_usage_login_events_result
|
|
CHECK (login_result IN ('success', 'failed')),
|
|
CONSTRAINT chk_usage_login_events_type
|
|
CHECK (login_type IN ('password', 'oauth', 'unknown'))
|
|
);
|
|
|
|
COMMENT ON TABLE usage_login_events IS '系统登录事件审计表:记录成功/失败登录,用于系统使用统计';
|
|
COMMENT ON COLUMN usage_login_events.user_id IS '登录成功时关联用户 ID;失败时允许为空';
|
|
COMMENT ON COLUMN usage_login_events.sub IS '登录标识快照,通常对应 sso_users.sub';
|
|
COMMENT ON COLUMN usage_login_events.department_name_snapshot IS '登录时的部门名称快照';
|
|
COMMENT ON COLUMN usage_login_events.area_snapshot IS '登录时的地区快照';
|
|
COMMENT ON COLUMN usage_login_events.login_result IS '登录结果:success / failed';
|
|
COMMENT ON COLUMN usage_login_events.login_type IS '登录方式:password / oauth / unknown';
|
|
COMMENT ON COLUMN usage_login_events.token_jti IS 'JWT 唯一标识,当前版本可为空';
|
|
COMMENT ON COLUMN usage_login_events.extra IS '扩展信息,预留后续登录来源、设备信息等';
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_login_time
|
|
ON usage_login_events(login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_user_id
|
|
ON usage_login_events(user_id, login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_department
|
|
ON usage_login_events(department_name_snapshot, login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_area
|
|
ON usage_login_events(area_snapshot, login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_result
|
|
ON usage_login_events(login_result, login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_type
|
|
ON usage_login_events(login_type, login_time DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_usage_login_events_sub
|
|
ON usage_login_events(sub, login_time DESC);
|
|
|
|
-- --------------------------------------------------------------------------
|
|
-- 3. 评查运行触发人索引
|
|
-- --------------------------------------------------------------------------
|
|
CREATE INDEX IF NOT EXISTS idx_leaudit_audit_runs_trigger_user_id
|
|
ON leaudit_audit_runs(trigger_user_id, created_at DESC);
|
|
|
|
COMMENT ON COLUMN leaudit_audit_runs.trigger_user_id IS '发起本次评查的用户 ID,用于用户/部门/地区维度统计';
|
|
|
|
-- --------------------------------------------------------------------------
|
|
-- 4. 历史回填(仅在存在成功登录记录时回填)
|
|
-- --------------------------------------------------------------------------
|
|
WITH latest_success_login AS (
|
|
SELECT
|
|
user_id,
|
|
MAX(login_time) AS last_login_at
|
|
FROM usage_login_events
|
|
WHERE user_id IS NOT NULL
|
|
AND login_result = 'success'
|
|
GROUP BY user_id
|
|
)
|
|
UPDATE sso_users u
|
|
SET last_login_at = l.last_login_at
|
|
FROM latest_success_login l
|
|
WHERE u.id = l.user_id
|
|
AND (u.last_login_at IS NULL OR u.last_login_at < l.last_login_at);
|
|
|
|
COMMIT;
|