添加jwt验证,添加交叉评查首页加载对接接口,评查任务文档列表对接接口,意见列表对接接口
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
import { createCookieSessionStorage } from "@remix-run/node";
|
||||
import { tokenManager } from "./token-manager.server";
|
||||
import { postgrestGet, postgrestPost, postgrestPut } from "../postgrest-client";
|
||||
import { JWTUtils, type UserInfoForJWT } from "~/utils/jwt";
|
||||
|
||||
/**
|
||||
* 用户角色类型定义
|
||||
@@ -132,6 +133,56 @@ export async function getSession(request: Request) {
|
||||
* - isTokenExpired: Token 是否已过期
|
||||
* - refreshedSession: 如果刷新了 Token,返回更新后的会话对象
|
||||
*/
|
||||
/**
|
||||
* 生成前端JWT
|
||||
* @param userInfo 用户信息
|
||||
* @param expiresIn OAuth token过期时间(秒)
|
||||
* @returns JWT字符串
|
||||
*/
|
||||
async function generateFrontendJWT(userInfo: UserInfo, savedUserData: SsoUser, userRole: UserRole, expiresIn: number): Promise<string> {
|
||||
const jwtUserInfo: UserInfoForJWT = {
|
||||
sub: userInfo.sub,
|
||||
user_id: savedUserData.id!,
|
||||
username: savedUserData.username,
|
||||
nick_name: savedUserData.nick_name,
|
||||
email: savedUserData.email,
|
||||
phone_number: savedUserData.phone_number,
|
||||
ou_id: savedUserData.ou_id,
|
||||
ou_name: savedUserData.ou_name,
|
||||
is_leader: savedUserData.is_leader,
|
||||
user_role: userRole
|
||||
};
|
||||
|
||||
return JWTUtils.generateJWT(jwtUserInfo, expiresIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建包含JWT的用户信息对象
|
||||
* @param userInfo OAuth用户信息
|
||||
* @param savedUserData 数据库中保存的用户数据
|
||||
* @param userRole 用户角色
|
||||
* @param frontendJWT 前端JWT
|
||||
* @returns 完整的用户信息对象
|
||||
*/
|
||||
function createUserInfoWithJWT(userInfo: UserInfo, savedUserData: SsoUser, userRole: UserRole, frontendJWT: string) {
|
||||
return {
|
||||
// 保持与callback.tsx中enhancedUserInfo相同的数据结构
|
||||
sub: userInfo.sub,
|
||||
username: savedUserData.username,
|
||||
nick_name: savedUserData.nick_name,
|
||||
phone_number: savedUserData.phone_number,
|
||||
email: savedUserData.email,
|
||||
ou_id: savedUserData.ou_id,
|
||||
ou_name: savedUserData.ou_name,
|
||||
status: savedUserData.status,
|
||||
is_leader: savedUserData.is_leader,
|
||||
// 增强字段,与OAuth登录保持一致
|
||||
user_id: savedUserData.id,
|
||||
user_role: userRole,
|
||||
frontend_jwt: frontendJWT
|
||||
};
|
||||
}
|
||||
|
||||
export async function getUserSession(request: Request) {
|
||||
const session = await getSession(request);
|
||||
const isAuthenticated = session.get("isAuthenticated") === true;
|
||||
@@ -141,9 +192,11 @@ export async function getUserSession(request: Request) {
|
||||
let tokenIssuedAt = session.get("tokenIssuedAt");
|
||||
let tokenExpiresIn = session.get("tokenExpiresIn");
|
||||
const userInfo = session.get("userInfo");
|
||||
let frontendJWT = session.get("frontendJWT");
|
||||
|
||||
let isTokenExpired = false;
|
||||
let refreshedSession = null;
|
||||
let shouldRegenerateJWT = false;
|
||||
|
||||
// 如果有token信息,检查是否需要刷新
|
||||
if (accessToken && refreshToken && tokenIssuedAt && tokenExpiresIn) {
|
||||
@@ -175,6 +228,9 @@ export async function getUserSession(request: Request) {
|
||||
tokenIssuedAt = newToken.tokenIssuedAt;
|
||||
tokenExpiresIn = newToken.tokenExpiresIn;
|
||||
|
||||
// 标记需要重新生成JWT
|
||||
shouldRegenerateJWT = true;
|
||||
|
||||
refreshedSession = session;
|
||||
}
|
||||
|
||||
@@ -189,6 +245,77 @@ export async function getUserSession(request: Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// 检查前端JWT状态
|
||||
if (isAuthenticated && !isTokenExpired && userInfo) {
|
||||
let needsJWTRefresh = false;
|
||||
|
||||
// 检查是否有前端JWT
|
||||
if (!frontendJWT) {
|
||||
needsJWTRefresh = true;
|
||||
console.log("缺少前端JWT,需要生成");
|
||||
} else {
|
||||
// 检查JWT是否即将过期
|
||||
if (JWTUtils.isJWTExpiringSoon(frontendJWT)) {
|
||||
needsJWTRefresh = true;
|
||||
console.log("前端JWT即将过期,需要重新生成");
|
||||
}
|
||||
}
|
||||
|
||||
// 如果OAuth token被刷新了,也需要重新生成JWT
|
||||
if (shouldRegenerateJWT) {
|
||||
needsJWTRefresh = true;
|
||||
console.log("OAuth token已刷新,需要重新生成JWT");
|
||||
}
|
||||
|
||||
// 重新生成JWT
|
||||
if (needsJWTRefresh && tokenExpiresIn) {
|
||||
try {
|
||||
// 从userInfo中获取用户数据
|
||||
if (userInfo.user_id && userInfo.sub) {
|
||||
const mockSavedUserData: SsoUser = {
|
||||
id: userInfo.user_id,
|
||||
sub: userInfo.sub,
|
||||
username: userInfo.username || userInfo.sub,
|
||||
nick_name: userInfo.nick_name || "未知用户",
|
||||
phone_number: userInfo.phone_number,
|
||||
email: userInfo.email,
|
||||
ou_id: userInfo.ou_id || "default",
|
||||
ou_name: userInfo.ou_name || "未知部门",
|
||||
status: 0,
|
||||
is_leader: userInfo.is_leader || false
|
||||
};
|
||||
|
||||
const newJWT = await generateFrontendJWT(userInfo, mockSavedUserData, userRole, tokenExpiresIn);
|
||||
|
||||
// 打印JWT重新生成信息
|
||||
console.log("=== Token刷新时重新生成JWT ===");
|
||||
console.log("原始userInfo:", userInfo);
|
||||
console.log("重构的用户数据:", mockSavedUserData);
|
||||
console.log("用户角色:", userRole);
|
||||
console.log("新生成的JWT:", newJWT);
|
||||
console.log("JWT过期时间:", JWTUtils.getJWTExpiration(newJWT));
|
||||
|
||||
// 更新session中的JWT
|
||||
if (!refreshedSession) {
|
||||
refreshedSession = session;
|
||||
}
|
||||
refreshedSession.set("frontendJWT", newJWT);
|
||||
|
||||
// 更新userInfo以包含新的JWT
|
||||
const updatedUserInfo = createUserInfoWithJWT(userInfo, mockSavedUserData, userRole, newJWT);
|
||||
refreshedSession.set("userInfo", updatedUserInfo);
|
||||
|
||||
console.log("更新后的userInfo:", updatedUserInfo);
|
||||
console.log("=== JWT重新生成完成 ===");
|
||||
|
||||
frontendJWT = newJWT;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("生成前端JWT失败:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isAuthenticated: isAuthenticated && !isTokenExpired,
|
||||
userRole,
|
||||
@@ -196,7 +323,8 @@ export async function getUserSession(request: Request) {
|
||||
refreshToken,
|
||||
userInfo,
|
||||
isTokenExpired,
|
||||
refreshedSession // 如果刷新了token,返回更新后的session
|
||||
refreshedSession, // 如果刷新了token,返回更新后的session
|
||||
frontendJWT // 返回前端JWT
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user