fix: 修改单点登录保存用户的jwt的生成,通过user_id为login,绕过验证进行表的增改。

This commit is contained in:
2025-11-11 21:09:11 +08:00
parent 12ec2ad7bd
commit c20c168a13
4 changed files with 53 additions and 46 deletions
+40 -12
View File
@@ -48,6 +48,7 @@ export interface UserInfo {
status?: number; // 账户状态: 0=正常, 1=禁用
is_leader?: boolean; // 是否为部门负责人
area?: string; // 用户所属地区
id?: string | number; // 临时的用户id
}
/**
@@ -538,16 +539,24 @@ async function callIDaaSLogout(accessToken: string, appId: string): Promise<void
* 保存用户信息到数据库
*
* 此函数实现以下逻辑:
* 1. 根据 userInfo.sub 查询 sso_users 表中是否已存在该用户
* 2. 如果存在,则更新用户信息(如果用户已有 area 值则不更新)
* 3. 如果存在,则插入新的用户记录
* 1. 内部生成临时 JWTuser_id 为 'login',仅用于数据库操作)
* 2. 根据 userInfo.sub 查询 sso_users 表中是否已存在该用户
* 3. 如果存在,则更新用户信息(如果用户已有 area 值则不更新)
* 4. 如果不存在,则插入新的用户记录
* 5. 返回保存的用户数据和临时 JWT
*
* @param userInfo - 从 IDaaS 获取的用户信息
* @param token - JWT令牌
* @param userRole - 用户角色
* @param tokenExpiresIn - Token过期时间(秒)
* @param area - 用户所属地区,根据端口号确定
* @returns Promise<{success: boolean, data?: SsoUser, error?: string}>
* @returns Promise<{success: boolean, data?: SsoUser, tempToken?: string, error?: string}>
*/
export async function saveUserInfo(userInfo: UserInfo, token?: string, area?: string): Promise<{success: boolean, data?: SsoUser, error?: string}> {
export async function saveUserInfo(
userInfo: UserInfo,
userRole: UserRole,
tokenExpiresIn: number,
area?: string
): Promise<{success: boolean, data?: SsoUser, tempToken?: string, error?: string}> {
try {
console.log("开始保存用户信息", userInfo);
@@ -556,13 +565,30 @@ export async function saveUserInfo(userInfo: UserInfo, token?: string, area?: st
return { success: false, error: "用户唯一标识 sub 不能为空" };
}
// 🔒 安全:在服务端生成临时 JWT,user_id 使用占位符 'login'
// 这样客户端无法看到真实的 user_id
const tempUserInfo: UserInfoForJWT = {
sub: userInfo.sub,
user_id: 'login', // 使用占位符,避免在客户端暴露真实ID
username: 'login',
nick_name: userInfo.nick_name || userInfo.nickname || userInfo.name || "未知用户",
email: userInfo.email,
phone_number: userInfo.phone_number,
ou_id: userInfo.ou_id || "default",
ou_name: userInfo.ou_name || "未知部门",
is_leader: userInfo.is_leader || false,
user_role: userRole
};
const tempToken = JWTUtils.generateJWT(tempUserInfo, tokenExpiresIn);
// 1. 根据 sub 查询是否已存在该用户
const existingUserResult = await postgrestGet<SsoUser[]>("sso_users", {
filter: {
"sub": `eq.${userInfo.sub}`,
"deleted_at": "is.null" // 只查询未删除的记录
},
token
token: tempToken
});
if (existingUserResult.error) {
@@ -603,7 +629,7 @@ export async function saveUserInfo(userInfo: UserInfo, token?: string, area?: st
"sso_users",
userData,
{ id: existingUser.id! },
token
tempToken
);
if (updateResult.error) {
@@ -614,7 +640,8 @@ export async function saveUserInfo(userInfo: UserInfo, token?: string, area?: st
console.log("用户信息更新成功");
return {
success: true,
data: Array.isArray(updateResult.data) ? updateResult.data[0] : updateResult.data as unknown as SsoUser
data: Array.isArray(updateResult.data) ? updateResult.data[0] : updateResult.data as unknown as SsoUser,
tempToken // 返回临时 JWT
};
} else {
// 3. 用户不存在,执行插入操作,设置地区信息
@@ -626,7 +653,7 @@ export async function saveUserInfo(userInfo: UserInfo, token?: string, area?: st
console.log("新用户,设置地区为:", area);
}
const insertResult = await postgrestPost<SsoUser[], SsoUser>("sso_users", userData as SsoUser, token);
const insertResult = await postgrestPost<SsoUser[], SsoUser>("sso_users", userData as SsoUser, tempToken);
if (insertResult.error) {
console.error("插入用户失败:", insertResult.error);
@@ -638,12 +665,13 @@ export async function saveUserInfo(userInfo: UserInfo, token?: string, area?: st
// 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, token);
await addDefaultRole(userData_with_id.id, 2, tempToken);
}
return {
success: true,
data: userData_with_id
data: userData_with_id,
tempToken // 返回临时 JWT
};
}
} catch (error) {