288 lines
14 KiB
PL/PgSQL
288 lines
14 KiB
PL/PgSQL
-- ==========================================================================
|
||
-- LeAudit Platform RBAC / User Schema Patch
|
||
-- 目标:在当前 leaudit_platform 新库中补齐用户、角色、权限、路由核心表
|
||
-- 设计原则:
|
||
-- 1. 兼容老系统 docauditai 的核心字段语义
|
||
-- 2. 新系统只做单地区隔离,地区字段统一使用 sso_users.area
|
||
-- 3. 采用 bigint 主键,兼容新库现有 leaudit_* bigint 引用字段
|
||
-- 4. 当前库里尚不存在 sso_users / roles / permissions / role_permissions / sys_routes / role_route / user_role
|
||
-- ============================================================================
|
||
|
||
BEGIN;
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 1. 用户主表 sso_users
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS sso_users (
|
||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||
sub VARCHAR(128) NOT NULL,
|
||
username VARCHAR(128) NOT NULL,
|
||
nick_name VARCHAR(128) NOT NULL,
|
||
phone_number VARCHAR(64),
|
||
email VARCHAR(256),
|
||
ou_id VARCHAR(128) NOT NULL,
|
||
ou_name VARCHAR(255) NOT NULL,
|
||
status SMALLINT NOT NULL DEFAULT 0,
|
||
is_leader BOOLEAN NOT NULL DEFAULT FALSE,
|
||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITHOUT TIME ZONE,
|
||
password VARCHAR(255),
|
||
try_count INTEGER,
|
||
try_login_time TIMESTAMP WITHOUT TIME ZONE,
|
||
area VARCHAR(64),
|
||
mq_person_uuid VARCHAR(64),
|
||
mq_account_uuid VARCHAR(64),
|
||
mq_synced_at TIMESTAMP WITHOUT TIME ZONE,
|
||
tenant_name VARCHAR(255),
|
||
dep_short_name VARCHAR(255),
|
||
dep_name VARCHAR(255),
|
||
CONSTRAINT sso_users_sub_key UNIQUE (sub)
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_sso_users_sub ON sso_users(sub);
|
||
CREATE UNIQUE INDEX IF NOT EXISTS idx_sso_users_sub_unique ON sso_users(sub);
|
||
CREATE INDEX IF NOT EXISTS idx_sso_users_username ON sso_users(username);
|
||
CREATE INDEX IF NOT EXISTS idx_sso_users_area ON sso_users(area) WHERE area IS NOT NULL;
|
||
CREATE INDEX IF NOT EXISTS idx_sso_users_status ON sso_users(status);
|
||
CREATE INDEX IF NOT EXISTS idx_sso_users_deleted_at ON sso_users(deleted_at);
|
||
CREATE INDEX IF NOT EXISTS idx_sso_users_ou_id ON sso_users(ou_id);
|
||
CREATE INDEX IF NOT EXISTS idx_sso_users_is_leader ON sso_users(is_leader);
|
||
CREATE INDEX IF NOT EXISTS idx_sso_users_mq_person ON sso_users(mq_person_uuid);
|
||
CREATE INDEX IF NOT EXISTS idx_sso_users_mq_account ON sso_users(mq_account_uuid);
|
||
|
||
COMMENT ON TABLE sso_users IS '用户主表:认证身份、组织信息、地区隔离基础字段统一沉淀在这里';
|
||
COMMENT ON COLUMN sso_users.sub IS '统一身份唯一标识,OAuth / SSO 主键';
|
||
COMMENT ON COLUMN sso_users.username IS '登录名/工号/展示账号';
|
||
COMMENT ON COLUMN sso_users.nick_name IS '用户真实姓名';
|
||
COMMENT ON COLUMN sso_users.area IS '用户主地区,当前系统唯一数据隔离字段';
|
||
COMMENT ON COLUMN sso_users.password IS '密码字段:当前阶段兼容旧值,后续应迁移为哈希';
|
||
COMMENT ON COLUMN sso_users.status IS '账户状态:0=正常,1=禁用';
|
||
COMMENT ON COLUMN sso_users.deleted_at IS '软删除时间';
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 2. 角色表 roles
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS roles (
|
||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||
role_key VARCHAR(64) NOT NULL,
|
||
role_name VARCHAR(128) NOT NULL,
|
||
data_scope VARCHAR(16) DEFAULT 'SELF',
|
||
description VARCHAR(255) DEFAULT '',
|
||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||
parent_role_id BIGINT,
|
||
priority INTEGER DEFAULT 0,
|
||
is_system_role BOOLEAN DEFAULT FALSE,
|
||
permissions_cache JSONB,
|
||
metadata JSONB,
|
||
CONSTRAINT roles_role_key_key UNIQUE (role_key),
|
||
CONSTRAINT fk_parent_role FOREIGN KEY (parent_role_id) REFERENCES roles(id) ON DELETE SET NULL,
|
||
CONSTRAINT chk_roles_data_scope CHECK (data_scope IN ('ALL', 'DEPT', 'SELF', 'GROUP'))
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_roles_parent_role_id ON roles(parent_role_id);
|
||
CREATE INDEX IF NOT EXISTS idx_roles_priority ON roles(priority DESC);
|
||
CREATE INDEX IF NOT EXISTS idx_roles_permissions_cache ON roles USING GIN (permissions_cache);
|
||
|
||
COMMENT ON TABLE roles IS '角色表:当前主业务角色只使用 provincial_admin/admin/common,可选 super_admin';
|
||
COMMENT ON COLUMN roles.role_key IS '角色机器标识,例如 provincial_admin/admin/common';
|
||
COMMENT ON COLUMN roles.role_name IS '角色展示名称';
|
||
COMMENT ON COLUMN roles.data_scope IS '默认数据范围:ALL/DEPT/SELF;GROUP 仅保留兼容';
|
||
COMMENT ON COLUMN roles.priority IS '角色优先级,数值越大优先级越高';
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 3. 菜单/路由表 sys_routes
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS sys_routes (
|
||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||
route_path VARCHAR(255) NOT NULL,
|
||
route_name VARCHAR(128) NOT NULL,
|
||
component VARCHAR(255),
|
||
parent_id BIGINT,
|
||
route_title VARCHAR(255),
|
||
icon VARCHAR(128),
|
||
sort_order INTEGER DEFAULT 0,
|
||
is_hidden BOOLEAN DEFAULT FALSE,
|
||
is_cache BOOLEAN DEFAULT TRUE,
|
||
meta JSONB,
|
||
status INTEGER DEFAULT 0,
|
||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
deleted_at TIMESTAMP WITHOUT TIME ZONE,
|
||
CONSTRAINT fk_parent_route FOREIGN KEY (parent_id) REFERENCES sys_routes(id) ON DELETE SET NULL
|
||
);
|
||
|
||
CREATE UNIQUE INDEX IF NOT EXISTS idx_routes_path ON sys_routes(route_path) WHERE deleted_at IS NULL;
|
||
CREATE INDEX IF NOT EXISTS idx_routes_parent_id ON sys_routes(parent_id);
|
||
CREATE INDEX IF NOT EXISTS idx_routes_status ON sys_routes(status);
|
||
|
||
COMMENT ON TABLE sys_routes IS '前端菜单/页面路由表:用于控制角色可见菜单,不替代 API 权限表';
|
||
COMMENT ON COLUMN sys_routes.route_path IS '前端路由路径';
|
||
COMMENT ON COLUMN sys_routes.status IS '状态:0=启用,1=禁用';
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 4. 角色路由关系表 role_route
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS role_route (
|
||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||
role_id BIGINT NOT NULL,
|
||
route_id BIGINT NOT NULL,
|
||
permission VARCHAR(8) DEFAULT 'RW',
|
||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||
status SMALLINT NOT NULL DEFAULT 1,
|
||
CONSTRAINT role_route_role_id_route_id_key UNIQUE (role_id, route_id),
|
||
CONSTRAINT fk_role_route_role FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
|
||
CONSTRAINT fk_role_route_route FOREIGN KEY (route_id) REFERENCES sys_routes(id) ON DELETE CASCADE,
|
||
CONSTRAINT chk_role_route_status CHECK (status IN (0, 1)),
|
||
CONSTRAINT chk_role_route_permission CHECK (permission IN ('R', 'W', 'RW'))
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_role_route_status ON role_route(status);
|
||
CREATE INDEX IF NOT EXISTS idx_role_route_role_status ON role_route(role_id, status);
|
||
|
||
COMMENT ON TABLE role_route IS '角色与菜单路由关联表';
|
||
COMMENT ON COLUMN role_route.permission IS '路由权限类型:R=读,W=写,RW=读写';
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 5. 权限点表 permissions
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS permissions (
|
||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||
permission_key VARCHAR(100) NOT NULL,
|
||
module VARCHAR(50) NOT NULL,
|
||
resource VARCHAR(50) NOT NULL,
|
||
action VARCHAR(50) NOT NULL,
|
||
description TEXT,
|
||
display_name VARCHAR(200),
|
||
permission_type VARCHAR(20) NOT NULL DEFAULT 'API',
|
||
is_system BOOLEAN NOT NULL DEFAULT FALSE,
|
||
metadata JSONB,
|
||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
created_by BIGINT,
|
||
updated_by BIGINT,
|
||
parent_id BIGINT,
|
||
sort_order INTEGER DEFAULT 0,
|
||
route_id BIGINT,
|
||
api_path VARCHAR(255),
|
||
api_method VARCHAR(16),
|
||
related_routes BIGINT[],
|
||
CONSTRAINT permissions_permission_key_key UNIQUE (permission_key),
|
||
CONSTRAINT permissions_parent_id_fkey FOREIGN KEY (parent_id) REFERENCES permissions(id) ON DELETE SET NULL,
|
||
CONSTRAINT permissions_route_id_fkey FOREIGN KEY (route_id) REFERENCES sys_routes(id) ON DELETE SET NULL,
|
||
CONSTRAINT permissions_key_format_check CHECK (permission_key ~ '^[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]+:[a-zA-Z0-9_*]+$')
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_permissions_module ON permissions(module);
|
||
CREATE INDEX IF NOT EXISTS idx_permissions_parent_id ON permissions(parent_id);
|
||
CREATE INDEX IF NOT EXISTS idx_permissions_route_id ON permissions(route_id);
|
||
CREATE INDEX IF NOT EXISTS idx_permissions_sort_order ON permissions(sort_order);
|
||
CREATE INDEX IF NOT EXISTS idx_permissions_system ON permissions(is_system);
|
||
CREATE INDEX IF NOT EXISTS idx_permissions_type ON permissions(permission_type);
|
||
CREATE INDEX IF NOT EXISTS idx_permissions_metadata ON permissions USING GIN (metadata);
|
||
|
||
COMMENT ON TABLE permissions IS '权限点定义表:统一使用 module:resource:action 风格 permission_key';
|
||
COMMENT ON COLUMN permissions.permission_key IS '权限键,例如 documents:list:read、audit:run:execute';
|
||
COMMENT ON COLUMN permissions.related_routes IS '共享权限可关联多个路由 ID';
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 6. 角色权限关系表 role_permissions
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS role_permissions (
|
||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||
role_id BIGINT NOT NULL,
|
||
permission_id BIGINT NOT NULL,
|
||
grant_type VARCHAR(10) NOT NULL DEFAULT 'GRANT',
|
||
data_scope VARCHAR(20),
|
||
condition_filter JSONB,
|
||
metadata JSONB,
|
||
created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
created_by BIGINT,
|
||
updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
||
updated_by BIGINT,
|
||
CONSTRAINT unique_role_permission UNIQUE (role_id, permission_id),
|
||
CONSTRAINT role_permissions_role_id_fkey FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
|
||
CONSTRAINT role_permissions_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE,
|
||
CONSTRAINT chk_role_permissions_grant_type CHECK (grant_type IN ('GRANT', 'DENY')),
|
||
CONSTRAINT chk_role_permissions_data_scope CHECK (data_scope IS NULL OR data_scope IN ('ALL', 'DEPT', 'SELF', 'GROUP'))
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_role_permissions_role_id ON role_permissions(role_id);
|
||
CREATE INDEX IF NOT EXISTS idx_role_permissions_permission_id ON role_permissions(permission_id);
|
||
CREATE INDEX IF NOT EXISTS idx_role_permissions_grant_type ON role_permissions(grant_type);
|
||
CREATE INDEX IF NOT EXISTS idx_role_permissions_data_scope ON role_permissions(data_scope);
|
||
CREATE INDEX IF NOT EXISTS idx_role_permissions_lookup ON role_permissions(role_id, grant_type);
|
||
CREATE INDEX IF NOT EXISTS idx_role_permissions_condition ON role_permissions USING GIN (condition_filter);
|
||
|
||
COMMENT ON TABLE role_permissions IS '角色权限关联表:grant_type 兼容旧系统 DENY 语义,当前新系统默认只配置 GRANT';
|
||
COMMENT ON COLUMN role_permissions.data_scope IS '数据范围:ALL/DEPT/SELF,GROUP 仅保留兼容';
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 7. 用户角色关系表 user_role
|
||
-- --------------------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS user_role (
|
||
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||
user_id BIGINT NOT NULL,
|
||
role_id BIGINT NOT NULL,
|
||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||
CONSTRAINT user_role_user_id_role_id_key UNIQUE (user_id, role_id),
|
||
CONSTRAINT fk_user_role_user FOREIGN KEY (user_id) REFERENCES sso_users(id) ON DELETE CASCADE,
|
||
CONSTRAINT fk_user_role_role FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_user_role_user_role ON user_role(user_id, role_id);
|
||
|
||
COMMENT ON TABLE user_role IS '用户与角色关联表;一个用户允许挂多个角色';
|
||
|
||
-- --------------------------------------------------------------------------
|
||
-- 8. 给现有 leaudit_* 业务表补用户外键
|
||
-- 当前库中这些字段均为 bigint,且当前全为空,可安全补充外键。
|
||
-- --------------------------------------------------------------------------
|
||
DO $$
|
||
BEGIN
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM pg_constraint WHERE conname = 'fk_leaudit_document_files_created_by'
|
||
) THEN
|
||
ALTER TABLE leaudit_document_files
|
||
ADD CONSTRAINT fk_leaudit_document_files_created_by
|
||
FOREIGN KEY (created_by) REFERENCES sso_users(id) ON DELETE SET NULL;
|
||
END IF;
|
||
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM pg_constraint WHERE conname = 'fk_leaudit_audit_runs_trigger_user_id'
|
||
) THEN
|
||
ALTER TABLE leaudit_audit_runs
|
||
ADD CONSTRAINT fk_leaudit_audit_runs_trigger_user_id
|
||
FOREIGN KEY (trigger_user_id) REFERENCES sso_users(id) ON DELETE SET NULL;
|
||
END IF;
|
||
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM pg_constraint WHERE conname = 'fk_leaudit_rule_sets_owner_user_id'
|
||
) THEN
|
||
ALTER TABLE leaudit_rule_sets
|
||
ADD CONSTRAINT fk_leaudit_rule_sets_owner_user_id
|
||
FOREIGN KEY (owner_user_id) REFERENCES sso_users(id) ON DELETE SET NULL;
|
||
END IF;
|
||
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM pg_constraint WHERE conname = 'fk_leaudit_rule_versions_editor_user_id'
|
||
) THEN
|
||
ALTER TABLE leaudit_rule_versions
|
||
ADD CONSTRAINT fk_leaudit_rule_versions_editor_user_id
|
||
FOREIGN KEY (editor_user_id) REFERENCES sso_users(id) ON DELETE SET NULL;
|
||
END IF;
|
||
|
||
IF NOT EXISTS (
|
||
SELECT 1 FROM pg_constraint WHERE conname = 'fk_leaudit_rule_versions_publisher_user_id'
|
||
) THEN
|
||
ALTER TABLE leaudit_rule_versions
|
||
ADD CONSTRAINT fk_leaudit_rule_versions_publisher_user_id
|
||
FOREIGN KEY (publisher_user_id) REFERENCES sso_users(id) ON DELETE SET NULL;
|
||
END IF;
|
||
END $$;
|
||
|
||
COMMIT;
|