Merge branch 'PingChuan' into shiy-login
# Conflicts: # app/config/api-config.ts fix: 1. 修复无法加载数据的问题:没有从入口页中进来会缺少数据。 2. 加强后端接口关于token的校验错误和权限校验错误的管理。 feat: 1. 对接后端的数据看板的接口。 2. 将系统设置单独抽出来作为管理员的固定一个入口。
This commit is contained in:
+29
-132
@@ -455,15 +455,27 @@ export async function logout(request: Request) {
|
||||
const accessToken = session.get("accessToken");
|
||||
const appId = OAUTH_CONFIG.appId || 'idaasoauth2';
|
||||
|
||||
// 如果存在访问令牌,调用IDaaS单点登出
|
||||
console.log("🚪 [Logout] 开始登出流程...");
|
||||
console.log("🔑 [Logout] accessToken 存在:", !!accessToken);
|
||||
console.log("📱 [Logout] appId:", appId);
|
||||
|
||||
// 如果存在访问令牌,调用IDaaS单点登出(仅 OAuth 登录用户)
|
||||
if (accessToken && appId) {
|
||||
console.log("🌐 [Logout] OAuth 用户,准备调用 IDaaS 单点登出...");
|
||||
try {
|
||||
await callIDaaSLogout(accessToken, appId);
|
||||
console.log("IDaaS单点登出成功");
|
||||
console.log("✅ [Logout] IDaaS单点登出成功");
|
||||
} catch (error) {
|
||||
console.error("IDaaS单点登出失败:", error);
|
||||
console.error("❌ [Logout] IDaaS单点登出失败:");
|
||||
console.error(" 错误详情:", error);
|
||||
if (error instanceof Error) {
|
||||
console.error(" 错误消息:", error.message);
|
||||
console.error(" 错误堆栈:", error.stack);
|
||||
}
|
||||
// 即使IDaaS登出失败,也继续清除本地会话
|
||||
}
|
||||
} else {
|
||||
console.log("ℹ️ [Logout] 管理员登录用户,无需调用 IDaaS 登出");
|
||||
}
|
||||
|
||||
return new Response(null, {
|
||||
@@ -487,6 +499,11 @@ async function callIDaaSLogout(accessToken: string, appId: string): Promise<void
|
||||
const redirectUri = OAUTH_CONFIG.redirectUri || 'http://10.79.97.17/';
|
||||
const logoutUrl = `${serverUrl}/public/sp/slo/${appId}`;
|
||||
|
||||
console.log("📡 [callIDaaSLogout] 准备发送登出请求:");
|
||||
console.log(" 登出URL:", logoutUrl);
|
||||
console.log(" 重定向URL:", redirectUri);
|
||||
console.log(" accessToken:", accessToken ? `${accessToken.substring(0, 20)}...` : 'null');
|
||||
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('access_token', accessToken);
|
||||
formData.append('redirect_url', encodeURIComponent(redirectUri));
|
||||
@@ -498,13 +515,19 @@ async function callIDaaSLogout(accessToken: string, appId: string): Promise<void
|
||||
},
|
||||
});
|
||||
|
||||
console.log("IDaaS单点登出请求成功");
|
||||
console.log("✅ [callIDaaSLogout] IDaaS单点登出请求成功");
|
||||
console.log(" 响应状态:", response.status);
|
||||
console.log(" 响应数据:", response.data);
|
||||
} catch (error) {
|
||||
if (axios.isAxiosError(error)) {
|
||||
console.error("调用IDaaS登出接口失败:", error.response?.status, error.response?.statusText);
|
||||
console.error("❌ [callIDaaSLogout] 调用IDaaS登出接口失败:");
|
||||
console.error(" HTTP状态:", error.response?.status);
|
||||
console.error(" 状态文本:", error.response?.statusText);
|
||||
console.error(" 响应数据:", error.response?.data);
|
||||
console.error(" 请求配置:", error.config?.url, error.config?.method);
|
||||
throw new Error(`IDaaS登出失败: ${error.response?.status} ${error.response?.statusText}`);
|
||||
}
|
||||
console.error("调用IDaaS登出接口失败:", error);
|
||||
console.error("❌ [callIDaaSLogout] 调用IDaaS登出接口失败(非HTTP错误):", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -751,129 +774,3 @@ export async function getUserBySub(sub: string) {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 账号密码登录接口
|
||||
*
|
||||
* @param username - 用户名
|
||||
* @param password - 密码
|
||||
* @param redirectTo - 登录成功后重定向的URL
|
||||
* @returns HTTP重定向响应或错误响应
|
||||
*/
|
||||
export async function simpleRootLogin(
|
||||
username: string,
|
||||
password: string,
|
||||
redirectTo: string
|
||||
) {
|
||||
try {
|
||||
// 输入验证
|
||||
if (!username?.trim() || !password?.trim()) {
|
||||
return new Response(JSON.stringify({
|
||||
success: false,
|
||||
error: "用户名和密码不能为空"
|
||||
}), {
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
}
|
||||
|
||||
// 调用登录接口
|
||||
const loginResponse = await axios.post(`${API_BASE_URL}/password_login`, {
|
||||
sub: username.trim(),
|
||||
password: password.trim()
|
||||
}, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
});
|
||||
|
||||
const loginResult = loginResponse.data;
|
||||
console.log('登录接口返回', loginResult);
|
||||
|
||||
// 检查重试次数
|
||||
const retryCount = loginResult.retryCount || loginResult.retry_count || 0;
|
||||
console.log('登录重试次数:', retryCount);
|
||||
|
||||
if (loginResult.code === 0 && loginResult.data) {
|
||||
// 登录成功,构建用户信息
|
||||
const userData = loginResult.data;
|
||||
// console.log('管理员登录userData', userData);
|
||||
const userRole = userData.role; // 默认角色
|
||||
|
||||
// 生成模拟的OAuth token信息
|
||||
const mockTokenExpiresIn = 7200; // 2小时
|
||||
const mockAccessToken = `mock_access_token_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
const mockRefreshToken = `mock_refresh_token_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
// 生成前端JWT
|
||||
const jwtUserInfo: UserInfoForJWT = {
|
||||
sub: userData.sub,
|
||||
user_id: userData.user_id,
|
||||
username: userData.username,
|
||||
nick_name: userData.nick_name,
|
||||
email: userData.email,
|
||||
phone_number: userData.phone_number,
|
||||
ou_id: userData.ou_id,
|
||||
ou_name: userData.ou_name,
|
||||
is_leader: userData.is_leader,
|
||||
user_role: userRole
|
||||
};
|
||||
|
||||
const frontendJWT = JWTUtils.generateJWT(jwtUserInfo, mockTokenExpiresIn);
|
||||
|
||||
// 构建增强的用户信息对象
|
||||
const enhancedUserInfo = {
|
||||
...userData,
|
||||
user_id: userData.user_id,
|
||||
user_role: userRole,
|
||||
frontend_jwt: frontendJWT
|
||||
};
|
||||
|
||||
// 使用统一的session创建函数
|
||||
return createUserSession({
|
||||
isAuthenticated: true,
|
||||
userRole: userRole,
|
||||
redirectTo,
|
||||
accessToken: mockAccessToken,
|
||||
refreshToken: mockRefreshToken,
|
||||
tokenExpiresIn: mockTokenExpiresIn,
|
||||
userInfo: enhancedUserInfo,
|
||||
frontendJWT
|
||||
});
|
||||
} else {
|
||||
// 登录失败,检查账户是否被锁定
|
||||
let errorMsg = loginResult.msg || "登录失败,请检查用户名和密码";
|
||||
let isLocked = false;
|
||||
|
||||
// 检查是否因重试次数过多被锁定
|
||||
if (retryCount >= 5) {
|
||||
errorMsg = "账户已被锁定,密码错误次数过多,请联系管理员";
|
||||
isLocked = true;
|
||||
} else if (retryCount > 0) {
|
||||
// 显示剩余尝试次数
|
||||
const remainingAttempts = 5 - retryCount;
|
||||
errorMsg = `${loginResult.msg || "用户名或密码错误"},还有 ${remainingAttempts} 次尝试机会`;
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({
|
||||
success: false,
|
||||
error: errorMsg,
|
||||
retryCount: retryCount,
|
||||
isLocked: isLocked,
|
||||
remainingAttempts: isLocked ? 0 : (5 - retryCount)
|
||||
}), {
|
||||
status: isLocked ? 403 : 401, // 403 表示禁止访问(账户被锁)
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("登录请求失败:", error);
|
||||
return new Response(JSON.stringify({
|
||||
success: false,
|
||||
error: "登录请求失败,请稍后重试"
|
||||
}), {
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user