ai-query对接新版freesun-agent接口的分支
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

128 lines
3.8 KiB

'use strict';
const TOKEN_FORMAT_REGEXP = /^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$/;
const getToken = (ctx) => {
const { query = {}, header = {} } = ctx;
const authHeader = header.authorization || header.Authorization;
if (query.token) return query.token;
if (header.token) return header.token;
if (authHeader && /^Bearer\s+/i.test(authHeader)) {
return authHeader.replace(/^Bearer\s+/i, '').trim();
}
return '';
};
const getVerifyTokenPaths = (ctx) => {
const configuredPath = ctx?.app?.fs?.config?.tenderUser?.aiCenter?.verifyTokenPath || '/verify-token';
const paths = [configuredPath, '/verify-token', '/auth/verify-token'];
return [...new Set(paths.map((item) => String(item || '').trim()).filter(Boolean))];
};
const getProfilePaths = (ctx) => {
const configuredPath = ctx?.app?.fs?.config?.tenderUser?.aiCenter?.profilePath || '/profile';
const paths = [configuredPath, '/profile', '/auth/profile'];
return [...new Set(paths.map((item) => String(item || '').trim()).filter(Boolean))];
};
const resolveCenterVerifyUser = (centerResponse = {}) => {
const userInfo = centerResponse?.AIUserInfo
|| centerResponse?.data?.AIUserInfo
|| centerResponse?.userInfo
|| centerResponse?.data?.userInfo
|| centerResponse?.data
|| centerResponse;
if (!userInfo || typeof userInfo !== 'object') return null;
const userId = String(
userInfo?.pepUserId
|| userInfo?.pep_user_id
|| userInfo?.pepId
|| userInfo?.pep_id
|| userInfo?.id
|| userInfo?.userId
|| '',
).trim();
if (!userId) return null;
return userInfo;
};
const verifyByAiCenter = async (ctx, token) => {
const centerRequest = ctx?.app?.fs?.centerRequest;
if (!centerRequest) return null;
const paths = getVerifyTokenPaths(ctx);
for (const path of paths) {
try {
const centerResponse = await centerRequest.get(path, {
query: { token },
});
const userInfo = resolveCenterVerifyUser(centerResponse);
if (userInfo) return userInfo;
} catch (error) {
ctx.logger.warn(`[tenderUserAuth] verify token failed on ${path}: ${error?.message || error}`);
}
}
const profilePaths = getProfilePaths(ctx);
for (const path of profilePaths) {
try {
const centerResponse = await centerRequest.get(path, {
query: { token },
});
const userInfo = resolveCenterVerifyUser(centerResponse);
if (userInfo) return userInfo;
} catch (error) {
ctx.logger.warn(`[tenderUserAuth] profile fallback failed on ${path}: ${error?.message || error}`);
}
}
return null;
};
module.exports = async (ctx, next) => {
try {
ctx.fs = ctx.fs || {};
const token = getToken(ctx);
if (!token) {
ctx.throw(401, 'Unauthorized');
return;
}
let userInfo = null;
const redis = ctx?.app?.fs?.redis;
if (redis) {
const cachedUserInfo = await redis.get(`ai_center:token:${token}:user`);
if (cachedUserInfo) {
try {
userInfo = JSON.parse(cachedUserInfo);
} catch (error) {
userInfo = null;
}
}
}
if (!userInfo) {
userInfo = await verifyByAiCenter(ctx, token);
if (userInfo && redis) {
await redis.setex(
`ai_center:token:${token}:user`,
24 * 3600,
JSON.stringify(userInfo),
);
}
}
if (!userInfo) {
ctx.throw(401, 'Unauthorized');
return;
}
ctx.fs.curUser = {
token,
userInfo,
};
await next();
} catch (error) {
ctx.logger.error(error);
ctx.throw(error.status || 401, error.message || error);
}
};