文档列表documents添加用户id的限制,添加通过统一认证之后数据库中用户数据的添加和角色的添加,添加Sidebar菜单通过数据库请求获取

This commit is contained in:
2025-07-20 21:49:40 +08:00
parent e4ce41cebe
commit d8f3d98c70
17 changed files with 1630 additions and 199 deletions
+282
View File
@@ -8,6 +8,7 @@
* - OAuth2.0 Token 自动刷新
* - 用户登录状态检查
* - 会话创建和销毁
* - 用户信息保存到数据库
*
* 技术栈:
* - Remix Session Storage (Cookie-based)
@@ -18,6 +19,7 @@
import { createCookieSessionStorage } from "@remix-run/node";
import { tokenManager } from "./token-manager.server";
import { postgrestGet, postgrestPost, postgrestPut } from "../postgrest-client";
/**
* 用户角色类型定义
@@ -28,6 +30,42 @@ import { tokenManager } from "./token-manager.server";
*/
export type UserRole = 'common' | 'developer';
/**
* 用户信息接口,对应 sso_users 表结构
*/
export interface UserInfo {
sub: string; // IDaaS用户唯一标识
username?: string; // 显示用户名称/工号
nick_name?: string; // 用户真实姓名
nickname?: string; // OAuth返回的昵称字段
name?: string; // 用户姓名(通常映射到 nick_name)
phone_number?: string; // 手机号
email?: string; // 邮箱地址
ou_id?: string; // 所属组织单位ID
ou_name?: string; // 所属部门名称
status?: number; // 账户状态: 0=正常, 1=禁用
is_leader?: boolean; // 是否为部门负责人
}
/**
* sso_users 表记录接口
*/
export interface SsoUser {
id?: string;
sub: string;
username: string;
nick_name: string;
phone_number?: string;
email?: string;
ou_id: string;
ou_name: string;
status: number;
is_leader: boolean;
created_at?: string;
updated_at?: string;
deleted_at?: string;
}
/**
* 会话存储配置
*
@@ -230,4 +268,248 @@ export async function logout(request: Request) {
"Set-Cookie": await sessionStorage.destroySession(session), // 清除会话 Cookie
},
});
}
/**
* 保存用户信息到数据库
*
* 此函数实现以下逻辑:
* 1. 根据 userInfo.sub 查询 sso_users 表中是否已存在该用户
* 2. 如果存在,则更新用户信息
* 3. 如果不存在,则插入新的用户记录
*
* @param userInfo - 从 IDaaS 获取的用户信息
* @returns Promise<{success: boolean, data?: SsoUser, error?: string}>
*/
export async function saveUserInfo(userInfo: UserInfo): Promise<{success: boolean, data?: SsoUser, error?: string}> {
try {
console.log("开始保存用户信息", userInfo);
// 验证必要字段
if (!userInfo.sub) {
return { success: false, error: "用户唯一标识 sub 不能为空" };
}
// 1. 根据 sub 查询是否已存在该用户
const existingUserResult = await postgrestGet<SsoUser[]>("sso_users", {
filter: {
"sub": `eq.${userInfo.sub}`,
"deleted_at": "is.null" // 只查询未删除的记录
}
});
if (existingUserResult.error) {
console.error("查询用户失败:", existingUserResult.error);
return { success: false, error: `查询用户失败: ${existingUserResult.error}` };
}
const existingUsers = existingUserResult.data || [];
const existingUser = existingUsers.length > 0 ? existingUsers[0] : null;
// 准备要保存的用户数据
// 注意:OAuth返回的字段是nickname,而不是nick_name
const userData: Partial<SsoUser> = {
sub: userInfo.sub,
username: userInfo.username || userInfo.name || userInfo.sub,
nick_name: userInfo.nick_name || userInfo.nickname || userInfo.name || "未知用户",
phone_number: userInfo.phone_number || undefined,
email: userInfo.email || undefined,
ou_id: userInfo.ou_id || "default",
ou_name: userInfo.ou_name || "未知部门",
status: userInfo.status !== undefined ? userInfo.status : 0,
is_leader: userInfo.is_leader || false,
};
if (existingUser) {
// 2. 用户已存在,执行更新操作
console.log("用户已存在,执行更新操作", existingUser.id);
const updateResult = await postgrestPut<SsoUser[], Partial<SsoUser>>(
"sso_users",
userData,
{ id: existingUser.id! }
);
if (updateResult.error) {
console.error("更新用户失败:", updateResult.error);
return { success: false, error: `更新用户失败: ${updateResult.error}` };
}
console.log("用户信息更新成功");
return {
success: true,
data: Array.isArray(updateResult.data) ? updateResult.data[0] : updateResult.data as unknown as SsoUser
};
} else {
// 3. 用户不存在,执行插入操作 同时需要给这个用户默认添加一个角色,角色为common
console.log("用户不存在,执行插入操作");
const insertResult = await postgrestPost<SsoUser[], SsoUser>("sso_users", userData as SsoUser);
if (insertResult.error) {
console.error("插入用户失败:", insertResult.error);
return { success: false, error: `插入用户失败: ${insertResult.error}` };
}
console.log("用户信息插入成功");
// 4. 给这个用户默认添加一个角色,角色为common
const userData_with_id = Array.isArray(insertResult.data) ? insertResult.data[0] : insertResult.data as unknown as SsoUser;
if (userData_with_id?.id) {
await addDefaultRole(userData_with_id.id, 2);
}
return {
success: true,
data: userData_with_id
};
}
} catch (error) {
console.error("保存用户信息时发生错误:", error);
return {
success: false,
error: `保存用户信息失败: ${error instanceof Error ? error.message : String(error)}`
};
}
}
/**
* 为用户添加默认角色
*
* @param userId - 用户ID
* @param roleId - 角色ID,默认为2common角色)
* @returns 添加结果
*/
export async function addDefaultRole(userId: string, roleId: number = 2) {
try {
console.log(`为用户 ${userId} 添加默认角色 ${roleId}`);
// 检查用户是否已经有此角色
const existingRoleResult = await postgrestGet<Array<{id: number, user_id: string, role_id: number}>>("user_role", {
filter: {
user_id: `eq.${userId}`,
role_id: `eq.${roleId}`
}
});
if (existingRoleResult.error) {
console.error("查询用户角色失败:", existingRoleResult.error);
return { success: false, error: `查询用户角色失败: ${existingRoleResult.error}` };
}
const existingRoles = existingRoleResult.data || [];
if (existingRoles.length > 0) {
console.log("用户已经拥有此角色,跳过添加");
return { success: true, data: existingRoles[0] };
}
// 添加角色
const addRoleResult = await postgrestPost<Array<{id: number, user_id: string, role_id: number}>, {user_id: string, role_id: number}>("user_role", {
user_id: userId,
role_id: roleId
});
if (addRoleResult.error) {
console.error("添加用户角色失败:", addRoleResult.error);
return { success: false, error: `添加用户角色失败: ${addRoleResult.error}` };
}
console.log("用户角色添加成功");
return {
success: true,
data: Array.isArray(addRoleResult.data) ? addRoleResult.data[0] : addRoleResult.data
};
} catch (error) {
console.error("添加用户角色时发生错误:", error);
return {
success: false,
error: `添加用户角色失败: ${error instanceof Error ? error.message : String(error)}`
};
}
}
/**
* 通过用户sub获取用户信息
*
* @param sub - 用户的唯一标识
* @returns 用户信息
*/
export async function getUserBySub(sub: string) {
try {
console.log(`查询用户: ${sub}`);
const userResult = await postgrestGet<SsoUser[]>("sso_users", {
filter: {
sub: `eq.${sub}`
}
});
if (userResult.error) {
console.error("查询用户失败:", userResult.error);
return { success: false, error: `查询用户失败: ${userResult.error}` };
}
const users = userResult.data || [];
const user = users.length > 0 ? users[0] : null;
if (!user) {
return { success: false, error: "用户不存在" };
}
return { success: true, data: user };
} catch (error) {
console.error("查询用户时发生错误:", error);
return {
success: false,
error: `查询用户失败: ${error instanceof Error ? error.message : String(error)}`
};
}
}
/**
* 创建用户登录会话(支持用户信息)
*
* @param isAuthenticated - 是否已认证
* @param userRole - 用户角色
* @param redirectTo - 重定向URL
* @param userInfo - 可选的用户信息
* @returns HTTP重定向响应
*/
export async function createUserSessionWithInfo(
isAuthenticated: boolean,
userRole: UserRole,
redirectTo: string,
userInfo?: Partial<SsoUser>
) {
const session = await sessionStorage.getSession();
session.set("isAuthenticated", isAuthenticated);
session.set("userRole", userRole);
// 如果提供了用户信息,也保存到session中
if (userInfo) {
session.set("userInfo", {
sub: userInfo.sub,
user_id: userInfo.id,
username: userInfo.username,
nick_name: userInfo.nick_name,
email: userInfo.email,
ou_name: userInfo.ou_name,
is_leader: userInfo.is_leader,
user_role: userRole
});
}
const cookie = await sessionStorage.commitSession(session);
console.log("创建会话 - 设置Cookie:", !!cookie);
console.log("创建会话 - 用户角色:", userRole);
console.log("创建会话 - 用户信息:", userInfo?.username || "无");
console.log("创建会话 - 重定向到:", redirectTo);
return new Response(null, {
status: 302,
headers: {
Location: redirectTo,
"Set-Cookie": cookie,
},
});
}