Initial commit of akmon project
This commit is contained in:
601
supabase_auth_complete_setup.sql
Normal file
601
supabase_auth_complete_setup.sql
Normal file
@@ -0,0 +1,601 @@
|
||||
-- =====================================================
|
||||
-- Supabase Auth 完整角色管理与权限配置
|
||||
-- 适用于教师/学生消息系统的完整解决方案
|
||||
-- =====================================================
|
||||
|
||||
-- 清理和重置(谨慎使用)
|
||||
DO $$
|
||||
BEGIN
|
||||
-- 删除现有触发器
|
||||
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
|
||||
DROP TRIGGER IF EXISTS trigger_update_user_roles_updated_at ON public.user_roles;
|
||||
|
||||
-- 删除现有函数
|
||||
DROP FUNCTION IF EXISTS public.handle_new_user() CASCADE;
|
||||
DROP FUNCTION IF EXISTS public.update_user_roles_updated_at() CASCADE;
|
||||
DROP FUNCTION IF EXISTS public.update_user_role(UUID, TEXT, UUID) CASCADE;
|
||||
DROP FUNCTION IF EXISTS public.get_user_role(UUID) CASCADE;
|
||||
DROP FUNCTION IF EXISTS public.batch_update_user_roles(JSONB, UUID) CASCADE;
|
||||
DROP FUNCTION IF EXISTS public.sync_user_role_metadata(UUID) CASCADE;
|
||||
|
||||
-- 删除现有视图
|
||||
DROP VIEW IF EXISTS public.user_roles_with_email CASCADE;
|
||||
|
||||
RAISE NOTICE '🧹 已清理现有角色管理组件';
|
||||
END $$;
|
||||
|
||||
-- =====================================================
|
||||
-- 1. 核心角色管理表
|
||||
-- =====================================================
|
||||
|
||||
-- 创建用户角色管理表
|
||||
CREATE TABLE IF NOT EXISTS public.user_roles (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
role TEXT NOT NULL CHECK (role IN ('admin', 'teacher', 'student')),
|
||||
|
||||
-- 扩展字段支持更复杂的权限管理
|
||||
class_id UUID DEFAULT NULL,
|
||||
school_id UUID DEFAULT NULL,
|
||||
department TEXT DEFAULT NULL,
|
||||
permissions JSONB DEFAULT '{}'::jsonb,
|
||||
|
||||
-- 状态管理
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
expires_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,
|
||||
|
||||
-- 审计字段
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id),
|
||||
updated_by UUID REFERENCES auth.users(id),
|
||||
|
||||
-- 确保每个用户只有一个主要角色
|
||||
UNIQUE(user_id)
|
||||
);
|
||||
|
||||
-- 创建优化索引
|
||||
CREATE INDEX IF NOT EXISTS idx_user_roles_user_id ON public.user_roles(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_roles_role ON public.user_roles(role);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_roles_class_id ON public.user_roles(class_id) WHERE class_id IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_user_roles_active ON public.user_roles(is_active) WHERE is_active = true;
|
||||
CREATE INDEX IF NOT EXISTS idx_user_roles_expires ON public.user_roles(expires_at) WHERE expires_at IS NOT NULL;
|
||||
|
||||
-- =====================================================
|
||||
-- 2. 核心角色管理函数
|
||||
-- =====================================================
|
||||
|
||||
-- 更新时间戳触发器函数
|
||||
CREATE OR REPLACE FUNCTION public.update_user_roles_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
NEW.updated_by = COALESCE(auth.uid(), NEW.updated_by);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- 创建更新触发器
|
||||
CREATE TRIGGER trigger_update_user_roles_updated_at
|
||||
BEFORE UPDATE ON public.user_roles
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.update_user_roles_updated_at();
|
||||
|
||||
-- 同步用户角色到 auth.users 元数据的函数
|
||||
CREATE OR REPLACE FUNCTION public.sync_user_role_metadata(target_user_id UUID)
|
||||
RETURNS BOOLEAN AS $$
|
||||
DECLARE
|
||||
user_role_record RECORD;
|
||||
BEGIN
|
||||
-- 获取用户角色信息
|
||||
SELECT role, class_id, school_id, department, permissions, is_active
|
||||
INTO user_role_record
|
||||
FROM public.user_roles
|
||||
WHERE user_id = target_user_id AND is_active = true;
|
||||
|
||||
IF FOUND THEN
|
||||
-- 更新 auth.users 的元数据
|
||||
UPDATE auth.users
|
||||
SET raw_user_meta_data = COALESCE(raw_user_meta_data, '{}'::jsonb) ||
|
||||
jsonb_build_object(
|
||||
'user_role', user_role_record.role,
|
||||
'class_id', user_role_record.class_id,
|
||||
'school_id', user_role_record.school_id,
|
||||
'department', user_role_record.department,
|
||||
'permissions', user_role_record.permissions,
|
||||
'role_synced_at', extract(epoch from now())
|
||||
)
|
||||
WHERE id = target_user_id;
|
||||
|
||||
RETURN true;
|
||||
ELSE
|
||||
-- 用户没有活跃角色,清除角色信息
|
||||
UPDATE auth.users
|
||||
SET raw_user_meta_data = COALESCE(raw_user_meta_data, '{}'::jsonb) ||
|
||||
jsonb_build_object(
|
||||
'user_role', 'inactive',
|
||||
'role_synced_at', extract(epoch from now())
|
||||
)
|
||||
WHERE id = target_user_id;
|
||||
|
||||
RETURN false;
|
||||
END IF;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- 自动为新用户分配角色的函数
|
||||
CREATE OR REPLACE FUNCTION public.handle_new_user()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
user_role TEXT := 'student'; -- 默认角色
|
||||
user_email TEXT := NEW.email;
|
||||
user_domain TEXT;
|
||||
BEGIN
|
||||
-- 提取邮箱域名
|
||||
user_domain := split_part(user_email, '@', 2);
|
||||
|
||||
-- 根据邮箱域名或特定规则分配角色
|
||||
CASE
|
||||
WHEN user_domain IN ('teacher.edu', 'faculty.edu', 'staff.edu') THEN
|
||||
user_role := 'teacher';
|
||||
WHEN user_domain IN ('admin.edu', 'management.edu') THEN
|
||||
user_role := 'admin';
|
||||
WHEN user_email LIKE '%admin%' OR user_email LIKE '%manager%' THEN
|
||||
user_role := 'admin';
|
||||
WHEN user_email LIKE '%teacher%' OR user_email LIKE '%faculty%' THEN
|
||||
user_role := 'teacher';
|
||||
ELSE
|
||||
user_role := 'student';
|
||||
END CASE;
|
||||
|
||||
-- 插入角色记录
|
||||
INSERT INTO public.user_roles (user_id, role, created_by)
|
||||
VALUES (NEW.id, user_role, NEW.id);
|
||||
|
||||
-- 同步到元数据
|
||||
PERFORM public.sync_user_role_metadata(NEW.id);
|
||||
|
||||
RAISE NOTICE '✅ 为用户 % 分配角色: %', NEW.email, user_role;
|
||||
|
||||
RETURN NEW;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RAISE WARNING '⚠️ 为用户 % 分配角色失败: %', NEW.email, SQLERRM;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- 创建新用户触发器
|
||||
CREATE TRIGGER on_auth_user_created
|
||||
AFTER INSERT ON auth.users
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.handle_new_user();
|
||||
|
||||
-- =====================================================
|
||||
-- 3. 角色管理和查询函数
|
||||
-- =====================================================
|
||||
|
||||
-- 获取用户角色的函数(支持缓存)
|
||||
CREATE OR REPLACE FUNCTION public.get_user_role(target_user_id UUID DEFAULT auth.uid())
|
||||
RETURNS TEXT AS $$
|
||||
DECLARE
|
||||
user_role TEXT;
|
||||
cached_role TEXT;
|
||||
role_synced_at NUMERIC;
|
||||
BEGIN
|
||||
-- 如果没有用户ID,返回匿名
|
||||
IF target_user_id IS NULL THEN
|
||||
RETURN 'anonymous';
|
||||
END IF;
|
||||
|
||||
-- 尝试从 auth.users 元数据获取缓存角色
|
||||
SELECT
|
||||
raw_user_meta_data->>'user_role',
|
||||
(raw_user_meta_data->>'role_synced_at')::numeric
|
||||
INTO cached_role, role_synced_at
|
||||
FROM auth.users
|
||||
WHERE id = target_user_id;
|
||||
|
||||
-- 如果缓存新鲜(5分钟内),直接返回
|
||||
IF cached_role IS NOT NULL AND role_synced_at IS NOT NULL
|
||||
AND (extract(epoch from now()) - role_synced_at) < 300 THEN
|
||||
RETURN cached_role;
|
||||
END IF;
|
||||
|
||||
-- 从角色表获取最新角色
|
||||
SELECT role INTO user_role
|
||||
FROM public.user_roles
|
||||
WHERE user_id = target_user_id AND is_active = true;
|
||||
|
||||
-- 如果找到角色,同步到元数据
|
||||
IF FOUND THEN
|
||||
PERFORM public.sync_user_role_metadata(target_user_id);
|
||||
RETURN user_role;
|
||||
ELSE
|
||||
RETURN 'student'; -- 默认角色
|
||||
END IF;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- 更新用户角色的函数(权限检查)
|
||||
CREATE OR REPLACE FUNCTION public.update_user_role(
|
||||
target_user_id UUID,
|
||||
new_role TEXT,
|
||||
operator_user_id UUID DEFAULT auth.uid(),
|
||||
additional_data JSONB DEFAULT '{}'::jsonb
|
||||
)
|
||||
RETURNS BOOLEAN AS $$
|
||||
DECLARE
|
||||
operator_role TEXT;
|
||||
old_role TEXT;
|
||||
BEGIN
|
||||
-- 检查新角色是否有效
|
||||
IF new_role NOT IN ('admin', 'teacher', 'student') THEN
|
||||
RAISE EXCEPTION 'Invalid role: %. Must be admin, teacher, or student', new_role;
|
||||
END IF;
|
||||
|
||||
-- 获取操作者角色
|
||||
operator_role := public.get_user_role(operator_user_id);
|
||||
|
||||
-- 权限检查:只有管理员可以修改角色
|
||||
IF operator_role != 'admin' THEN
|
||||
RAISE EXCEPTION 'Permission denied. Only admins can update user roles';
|
||||
END IF;
|
||||
|
||||
-- 获取旧角色
|
||||
SELECT role INTO old_role FROM public.user_roles WHERE user_id = target_user_id;
|
||||
|
||||
-- 更新角色表
|
||||
INSERT INTO public.user_roles (
|
||||
user_id, role, class_id, school_id, department, permissions, updated_by
|
||||
) VALUES (
|
||||
target_user_id,
|
||||
new_role,
|
||||
COALESCE(additional_data->>'class_id', NULL)::uuid,
|
||||
COALESCE(additional_data->>'school_id', NULL)::uuid,
|
||||
additional_data->>'department',
|
||||
COALESCE(additional_data->'permissions', '{}'::jsonb),
|
||||
operator_user_id
|
||||
)
|
||||
ON CONFLICT (user_id) DO UPDATE SET
|
||||
role = EXCLUDED.role,
|
||||
class_id = COALESCE(EXCLUDED.class_id, user_roles.class_id),
|
||||
school_id = COALESCE(EXCLUDED.school_id, user_roles.school_id),
|
||||
department = COALESCE(EXCLUDED.department, user_roles.department),
|
||||
permissions = COALESCE(EXCLUDED.permissions, user_roles.permissions),
|
||||
updated_at = NOW(),
|
||||
updated_by = EXCLUDED.updated_by;
|
||||
|
||||
-- 同步到元数据
|
||||
PERFORM public.sync_user_role_metadata(target_user_id);
|
||||
|
||||
RAISE NOTICE '✅ 用户角色更新: % -> % (操作者: %)', old_role, new_role, operator_role;
|
||||
|
||||
RETURN true;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- 批量角色管理函数
|
||||
CREATE OR REPLACE FUNCTION public.batch_update_user_roles(
|
||||
role_updates JSONB,
|
||||
operator_user_id UUID DEFAULT auth.uid()
|
||||
)
|
||||
RETURNS TABLE(
|
||||
user_id UUID,
|
||||
email TEXT,
|
||||
old_role TEXT,
|
||||
new_role TEXT,
|
||||
success BOOLEAN,
|
||||
error_message TEXT
|
||||
) AS $$
|
||||
DECLARE
|
||||
update_record RECORD;
|
||||
operator_role TEXT;
|
||||
old_role_val TEXT;
|
||||
user_email_val TEXT;
|
||||
BEGIN
|
||||
-- 检查操作者权限
|
||||
operator_role := public.get_user_role(operator_user_id);
|
||||
|
||||
IF operator_role != 'admin' THEN
|
||||
RAISE EXCEPTION 'Permission denied. Only admins can batch update user roles';
|
||||
END IF;
|
||||
|
||||
-- 处理每个更新请求
|
||||
FOR update_record IN
|
||||
SELECT * FROM jsonb_to_recordset(role_updates)
|
||||
AS x(user_id UUID, role TEXT, class_id UUID, school_id UUID, department TEXT)
|
||||
LOOP
|
||||
-- 获取用户信息
|
||||
SELECT ur.role, au.email INTO old_role_val, user_email_val
|
||||
FROM public.user_roles ur
|
||||
RIGHT JOIN auth.users au ON au.id = ur.user_id
|
||||
WHERE au.id = update_record.user_id;
|
||||
|
||||
-- 尝试更新
|
||||
BEGIN
|
||||
PERFORM public.update_user_role(
|
||||
update_record.user_id,
|
||||
update_record.role,
|
||||
operator_user_id,
|
||||
jsonb_build_object(
|
||||
'class_id', update_record.class_id,
|
||||
'school_id', update_record.school_id,
|
||||
'department', update_record.department
|
||||
)
|
||||
);
|
||||
|
||||
RETURN QUERY SELECT
|
||||
update_record.user_id,
|
||||
user_email_val,
|
||||
old_role_val,
|
||||
update_record.role,
|
||||
true,
|
||||
NULL::TEXT;
|
||||
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
RETURN QUERY SELECT
|
||||
update_record.user_id,
|
||||
user_email_val,
|
||||
old_role_val,
|
||||
update_record.role,
|
||||
false,
|
||||
SQLERRM;
|
||||
END;
|
||||
END LOOP;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- =====================================================
|
||||
-- 4. 权限检查和验证函数
|
||||
-- =====================================================
|
||||
|
||||
-- 检查用户是否有特定权限
|
||||
CREATE OR REPLACE FUNCTION public.user_has_permission(
|
||||
permission_name TEXT,
|
||||
target_user_id UUID DEFAULT auth.uid()
|
||||
)
|
||||
RETURNS BOOLEAN AS $$
|
||||
DECLARE
|
||||
user_role TEXT;
|
||||
user_permissions JSONB;
|
||||
BEGIN
|
||||
-- 获取用户角色和权限
|
||||
SELECT role, permissions INTO user_role, user_permissions
|
||||
FROM public.user_roles
|
||||
WHERE user_id = target_user_id AND is_active = true;
|
||||
|
||||
-- 管理员拥有所有权限
|
||||
IF user_role = 'admin' THEN
|
||||
RETURN true;
|
||||
END IF;
|
||||
|
||||
-- 检查角色默认权限
|
||||
CASE user_role
|
||||
WHEN 'teacher' THEN
|
||||
IF permission_name IN ('send_message', 'view_student_messages', 'create_group') THEN
|
||||
RETURN true;
|
||||
END IF;
|
||||
WHEN 'student' THEN
|
||||
IF permission_name IN ('send_message', 'view_own_messages') THEN
|
||||
RETURN true;
|
||||
END IF;
|
||||
END CASE;
|
||||
|
||||
-- 检查自定义权限
|
||||
IF user_permissions IS NOT NULL THEN
|
||||
RETURN (user_permissions->permission_name)::boolean = true;
|
||||
END IF;
|
||||
|
||||
RETURN false;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- 检查用户是否可以访问特定资源
|
||||
CREATE OR REPLACE FUNCTION public.can_access_resource(
|
||||
resource_type TEXT,
|
||||
resource_id UUID,
|
||||
access_type TEXT DEFAULT 'read',
|
||||
target_user_id UUID DEFAULT auth.uid()
|
||||
)
|
||||
RETURNS BOOLEAN AS $$
|
||||
DECLARE
|
||||
user_role TEXT;
|
||||
BEGIN
|
||||
user_role := public.get_user_role(target_user_id);
|
||||
|
||||
-- 管理员可以访问所有资源
|
||||
IF user_role = 'admin' THEN
|
||||
RETURN true;
|
||||
END IF;
|
||||
|
||||
-- 根据资源类型和访问类型进行权限检查
|
||||
CASE resource_type
|
||||
WHEN 'message' THEN
|
||||
-- 检查消息访问权限
|
||||
RETURN EXISTS (
|
||||
SELECT 1 FROM public.ak_messages m
|
||||
WHERE m.id = resource_id
|
||||
AND (
|
||||
(m.sender_type = 'user' AND m.sender_id = target_user_id) OR
|
||||
(m.receiver_type = 'user' AND m.receiver_id = target_user_id) OR
|
||||
(m.receiver_type = 'group' AND m.receiver_id IN (
|
||||
SELECT group_id FROM public.ak_message_group_members
|
||||
WHERE user_id = target_user_id AND status = 'active'
|
||||
)) OR
|
||||
(m.receiver_type = 'broadcast')
|
||||
)
|
||||
);
|
||||
WHEN 'group' THEN
|
||||
-- 检查群组访问权限
|
||||
RETURN EXISTS (
|
||||
SELECT 1 FROM public.ak_message_group_members
|
||||
WHERE group_id = resource_id AND user_id = target_user_id AND status = 'active'
|
||||
);
|
||||
ELSE
|
||||
RETURN false;
|
||||
END CASE;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql SECURITY DEFINER;
|
||||
|
||||
-- =====================================================
|
||||
-- 5. 管理视图和查询
|
||||
-- =====================================================
|
||||
|
||||
-- 用户角色详细信息视图
|
||||
CREATE OR REPLACE VIEW public.user_roles_detailed AS
|
||||
SELECT
|
||||
ur.id,
|
||||
ur.user_id,
|
||||
ur.role,
|
||||
ur.class_id,
|
||||
ur.school_id,
|
||||
ur.department,
|
||||
ur.permissions,
|
||||
ur.is_active,
|
||||
ur.expires_at,
|
||||
ur.created_at,
|
||||
ur.updated_at,
|
||||
|
||||
-- 用户信息
|
||||
au.email,
|
||||
au.email_confirmed_at,
|
||||
au.last_sign_in_at,
|
||||
|
||||
-- 元数据同步状态
|
||||
au.raw_user_meta_data->>'user_role' as metadata_role,
|
||||
(au.raw_user_meta_data->>'role_synced_at')::numeric as role_synced_at,
|
||||
CASE
|
||||
WHEN ur.role = au.raw_user_meta_data->>'user_role' THEN true
|
||||
ELSE false
|
||||
END as role_synced,
|
||||
|
||||
-- 统计信息
|
||||
(SELECT COUNT(*) FROM public.ak_messages WHERE sender_id = ur.user_id) as sent_messages,
|
||||
(SELECT COUNT(*) FROM public.ak_message_recipients WHERE user_id = ur.user_id) as received_messages
|
||||
|
||||
FROM public.user_roles ur
|
||||
LEFT JOIN auth.users au ON au.id = ur.user_id;
|
||||
|
||||
-- =====================================================
|
||||
-- 6. RLS 策略 for user_roles 表
|
||||
-- =====================================================
|
||||
|
||||
ALTER TABLE public.user_roles ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 删除现有策略(所有可能的策略名称)
|
||||
DROP POLICY IF EXISTS "Users can view own role" ON public.user_roles;
|
||||
DROP POLICY IF EXISTS "users_can_view_own_role" ON public.user_roles;
|
||||
DROP POLICY IF EXISTS "Admins can manage all roles" ON public.user_roles;
|
||||
DROP POLICY IF EXISTS "admins_can_manage_all_roles" ON public.user_roles;
|
||||
DROP POLICY IF EXISTS "Teachers can view students in same class" ON public.user_roles;
|
||||
DROP POLICY IF EXISTS "teachers_can_view_class_roles" ON public.user_roles;
|
||||
|
||||
-- 用户可以查看自己的角色
|
||||
CREATE POLICY "users_can_view_own_role" ON public.user_roles
|
||||
FOR SELECT USING (auth.uid() = user_id);
|
||||
|
||||
-- 管理员可以查看和管理所有角色
|
||||
CREATE POLICY "admins_can_manage_all_roles" ON public.user_roles
|
||||
FOR ALL USING (
|
||||
public.get_user_role(auth.uid()) = 'admin'
|
||||
);
|
||||
|
||||
-- 教师可以查看同班学生的角色(如果有班级系统)
|
||||
CREATE POLICY "teachers_can_view_class_roles" ON public.user_roles
|
||||
FOR SELECT USING (
|
||||
public.get_user_role(auth.uid()) = 'teacher'
|
||||
AND class_id IS NOT NULL
|
||||
AND class_id IN (
|
||||
SELECT class_id FROM public.user_roles teacher_role
|
||||
WHERE teacher_role.user_id = auth.uid()
|
||||
AND teacher_role.role = 'teacher'
|
||||
)
|
||||
);
|
||||
|
||||
-- =====================================================
|
||||
-- 7. 初始化测试数据
|
||||
-- =====================================================
|
||||
|
||||
-- 清理现有测试数据
|
||||
DELETE FROM public.user_roles WHERE user_id IN (
|
||||
'7bf7378e-a027-473e-97ac-3460ed3f170a',
|
||||
'eed3824b-bba1-4309-8048-19d17367c084'
|
||||
);
|
||||
|
||||
-- 插入测试用户角色
|
||||
INSERT INTO public.user_roles (user_id, role, department, permissions, created_by) VALUES
|
||||
(
|
||||
'7bf7378e-a027-473e-97ac-3460ed3f170a', -- 教师用户ID
|
||||
'teacher',
|
||||
'Computer Science',
|
||||
'{"can_create_groups": true, "can_send_broadcasts": false, "can_moderate": true}'::jsonb,
|
||||
'7bf7378e-a027-473e-97ac-3460ed3f170a'
|
||||
),
|
||||
(
|
||||
'eed3824b-bba1-4309-8048-19d17367c084', -- 学生用户ID
|
||||
'student',
|
||||
'Computer Science',
|
||||
'{"can_create_groups": false, "can_send_broadcasts": false}'::jsonb,
|
||||
'eed3824b-bba1-4309-8048-19d17367c084'
|
||||
);
|
||||
|
||||
-- 同步到 auth.users 元数据
|
||||
SELECT public.sync_user_role_metadata('7bf7378e-a027-473e-97ac-3460ed3f170a');
|
||||
SELECT public.sync_user_role_metadata('eed3824b-bba1-4309-8048-19d17367c084');
|
||||
|
||||
-- =====================================================
|
||||
-- 8. 使用示例和测试查询
|
||||
-- =====================================================
|
||||
|
||||
/*
|
||||
-- 示例1:查询用户角色
|
||||
SELECT public.get_user_role('7bf7378e-a027-473e-97ac-3460ed3f170a');
|
||||
|
||||
-- 示例2:检查权限
|
||||
SELECT public.user_has_permission('send_message', '7bf7378e-a027-473e-97ac-3460ed3f170a');
|
||||
|
||||
-- 示例3:检查资源访问权限
|
||||
SELECT public.can_access_resource('message', 'some-message-id', 'read', auth.uid());
|
||||
|
||||
-- 示例4:更新用户角色(需要管理员权限)
|
||||
SELECT public.update_user_role(
|
||||
'eed3824b-bba1-4309-8048-19d17367c084',
|
||||
'teacher',
|
||||
auth.uid(),
|
||||
'{"department": "Mathematics", "class_id": "some-class-id"}'::jsonb
|
||||
);
|
||||
|
||||
-- 示例5:批量更新角色
|
||||
SELECT * FROM public.batch_update_user_roles(
|
||||
'[
|
||||
{
|
||||
"user_id": "eed3824b-bba1-4309-8048-19d17367c084",
|
||||
"role": "teacher",
|
||||
"department": "Mathematics"
|
||||
}
|
||||
]'::jsonb
|
||||
);
|
||||
|
||||
-- 示例6:查看用户详细信息
|
||||
SELECT * FROM public.user_roles_detailed
|
||||
WHERE email LIKE '%test%'
|
||||
ORDER BY created_at DESC;
|
||||
|
||||
-- 示例7:查看角色同步状态
|
||||
SELECT user_id, email, role, metadata_role, role_synced
|
||||
FROM public.user_roles_detailed
|
||||
WHERE NOT role_synced OR role_synced IS NULL;
|
||||
|
||||
-- 示例8:强制同步所有用户角色
|
||||
SELECT user_id, public.sync_user_role_metadata(user_id) as synced
|
||||
FROM public.user_roles;
|
||||
*/
|
||||
|
||||
-- 完成提示
|
||||
SELECT
|
||||
'✅ Supabase Auth 角色管理系统配置完成' as status,
|
||||
count(*) as total_roles,
|
||||
count(*) FILTER (WHERE role = 'admin') as admins,
|
||||
count(*) FILTER (WHERE role = 'teacher') as teachers,
|
||||
count(*) FILTER (WHERE role = 'student') as students
|
||||
FROM public.user_roles;
|
||||
Reference in New Issue
Block a user