这里的逻辑是一个人可以在多个团队中,但在每个团队的角色有可能是不一样的,当一个人同时存在2个或者多个团队中时,下拉列表中会有多个团队详情,切换团队会查询不同的成员和部门。
团队列表查询api实现代码:
import { NextAPI } from '@/service/middleware/entry';
import type { NextApiRequest, NextApiResponse } from 'next';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
import { getResourcePermission } from '@fastgpt/service/support/permission/controller';
import { PerResourceTypeEnum } from '@fastgpt/global/support/permission/constant';
import { TeamPermission } from '@fastgpt/global/support/permission/user/controller';
import { TeamDefaultPermissionVal } from '@fastgpt/global/support/permission/user/constant';
import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant';
import { TeamSchema } from '@fastgpt/global/support/user/team/type';async function handler(req: NextApiRequest, res: NextApiResponse) {try {const { userId } = await authCert({ req, authToken: true });let userInTeams = await MongoTeamMember.find({ userId }).populate<{ team: TeamSchema }>('team').lean();if (!userInTeams.length) {return res.status(404).json({ message: 'member not exist' });}const aggreTeam = await Promise.all(userInTeams.map(async (tmb) => await getTeam(tmb)));// console.log(aggreTeam, 'aggreTeam');return aggreTeam;} catch (error: any) {return res.status(500).json({ message: '服务器内部错误' });}
}async function getTeam(tmb: any) {const Per = await getResourcePermission({resourceType: PerResourceTypeEnum.team,teamId: tmb.teamId,tmbId: tmb._id});return {userId: String(tmb.userId),teamId: String(tmb.teamId),teamAvatar: tmb.team.avatar,teamName: tmb.team.name,memberName: tmb.name,avatar: tmb.avatar,balance: tmb.team.balance,tmbId: String(tmb._id),teamDomain: tmb.team?.teamDomain,role: tmb.role,status: tmb.status,permission: new TeamPermission({per: Per ?? TeamDefaultPermissionVal,isOwner: tmb.role === TeamMemberRoleEnum.owner}),notificationAccount: tmb.team.notificationAccount,lafAccount: tmb.team.lafAccount,openaiAccount: tmb.team.openaiAccount,externalWorkflowVariables: tmb.team.externalWorkflowVariables};
}
export default NextAPI(handler);
切换团队api接口代码:
import type { NextApiRequest, NextApiResponse } from 'next';
import { NextAPI } from '@/service/middleware/entry';
import { MongoTeam } from '@fastgpt/service/support/user/team/teamSchema';
import { createJWT, setCookie } from '@fastgpt/service/support/permission/controller';
import { authCert } from '@fastgpt/service/support/permission/auth/common';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';async function handler(req: NextApiRequest, res: NextApiResponse) {let { teamId } = req.body;// const team = await MongoTeam.findById(teamId);const { userId, isRoot } = await authCert({ req, authToken: true });const userTeam = await MongoTeamMember.findOne({ userId, teamId });const tmbId: any = userTeam?._id;const token = createJWT({_id: userId,team: {teamId,tmbId},isRoot});setCookie(res, token);
}export default NextAPI(handler);
这里主要的逻辑是通过userid和当前切换的teamid还有tmbid(也就是当前team的id)使用jwt去创建一个token,和用户登录的逻辑是一样的,只是使用的teamid不一样,其它接口调用的时候都是根据cookie里面的token又去用jwt解析验证的,开源代码里面有个文件有以下代码主要是用来解析验证的:
export async function parseHeaderCert({req,authToken = false,authRoot = false,authApiKey = false
}: AuthModeType) {// parse jwtasync function authCookieToken(cookie?: string, token?: string) {// 获取 cookieconst cookies = Cookie.parse(cookie || '');const cookieToken = token || cookies[TokenName];if (!cookieToken) {return Promise.reject(ERROR_ENUM.unAuthorization);}return await authJWT(cookieToken);}// from authorization get apikeyasync function parseAuthorization(authorization?: string) {if (!authorization) {return Promise.reject(ERROR_ENUM.unAuthorization);}// Bearer fastgpt-xxxx-appIdconst auth = authorization.split(' ')[1];if (!auth) {return Promise.reject(ERROR_ENUM.unAuthorization);}const { apikey, appId: authorizationAppid = '' } = await (async () => {const arr = auth.split('-');// abandonif (arr.length === 3) {return {apikey: `${arr[0]}-${arr[1]}`,appId: arr[2]};}if (arr.length === 2) {return {apikey: auth};}return Promise.reject(ERROR_ENUM.unAuthorization);})();// auth apikeyconst { teamId, tmbId, appId: apiKeyAppId = '', sourceName } = await authOpenApiKey({ apikey });return {uid: '',teamId,tmbId,apikey,appId: apiKeyAppId || authorizationAppid,sourceName};}// root userasync function parseRootKey(rootKey?: string) {if (!rootKey || !process.env.ROOT_KEY || rootKey !== process.env.ROOT_KEY) {return Promise.reject(ERROR_ENUM.unAuthorization);}}const { cookie, token, rootkey, authorization } = (req.headers || {}) as ReqHeaderAuthType;const { uid, teamId, tmbId, appId, openApiKey, authType, isRoot, sourceName } =await (async () => {if (authApiKey && authorization) {// apikey from authorizationconst authResponse = await parseAuthorization(authorization);return {uid: authResponse.uid,teamId: authResponse.teamId,tmbId: authResponse.tmbId,appId: authResponse.appId,openApiKey: authResponse.apikey,authType: AuthUserTypeEnum.apikey,sourceName: authResponse.sourceName};}if (authToken && (token || cookie)) {// user token(from fastgpt web)const res = await authCookieToken(cookie, token);return {uid: res.userId,teamId: res.teamId,tmbId: res.tmbId,appId: '',openApiKey: '',authType: AuthUserTypeEnum.token,isRoot: res.isRoot};}if (authRoot && rootkey) {await parseRootKey(rootkey);// root userreturn {uid: '',teamId: '',tmbId: '',appId: '',openApiKey: '',authType: AuthUserTypeEnum.root,isRoot: true};}return Promise.reject(ERROR_ENUM.unAuthorization);})();if (!authRoot && (!teamId || !tmbId)) {return Promise.reject(ERROR_ENUM.unAuthorization);}return {userId: String(uid),teamId: String(teamId),tmbId: String(tmbId),appId,authType,sourceName,apikey: openApiKey,isRoot: !!isRoot};
}
用户正常登录时主要是使用authCookieToken这个函数的逻辑,因为有token;
使用创建api密钥也就是前文教大家用过的fastGPT—前端开发获取api密钥调用机器人对话接口(HTML实现)-CSDN博客那种方法就是用parseAuthorization函数的方法去验证的;
parseRootKey是.env文件中的ROOT_KEY,env文件大概配置是这样:
mongo 数据库、PG 向量库、milvus 向量库都得有
PORT=3001
LOG_DEPTH=3
# 默认用户密码,用户名为 root,每次重启时会自动更新。
DEFAULT_ROOT_PSW=245ZXCV@qaz
# 数据库最大连接数
DB_MAX_LINK=5
# token
TOKEN_KEY=sadasgvfd
# 文件阅读时的秘钥
FILE_TOKEN_KEY=filetokenkey
# root key, 最高权限
ROOT_KEY=fdafasd
# openai 基本地址,可用作中转。
OPENAI_BASE_URL=http://10.165.182.205:3000/
# oneapi 地址,可以使用 oneapi 来实现多模型接入
ONEAPI_URL=http://10.165.182.205:3000/v1/
# 通用key。可以是 openai 的也可以是 oneapi 的。
# 此处逻辑:优先走 ONEAPI_URL,如果填写了 ONEAPI_URL,key 也需要是 ONEAPI 的 key
CHAT_API_KEY=sk-HSgxOJ390gdckdqvBd7e70C1CfA3479cA3A9D4E1F693D822
# mongo 数据库连接参数,本地开发时,mongo可能需要增加 directConnection=true 参数,才能连接上。
MONGODB_URI=mongodb://10.185.92.58:27017/fastgpt?authSource=admin&directConnection=true# 向量库优先级: pg > milvus
# PG 向量库连接参数
PG_URL=postgresql://user08:245ZXCV@qaz@10.195.162.55:5432/fastgpt
# milvus 向量库连接参数
MILVUS_ADDRESS=https://in03-78bd7f60e6e2a7c.api.gcp-us-west1.zillizcloud.com
MILVUS_TOKEN=133964348b00dfdawgsrhagwarge385c8c64a3ec16b1ab92d3c67dcc4e0370fb9dd15791bcd6dadaferagerwgseagrw56d# code sandbox url
SANDBOX_URL=https://fastgptsandbox.encloudx.com
# 商业版地址
PRO_URL=
# 首页路径
HOME_URL=/
# 日志等级: debug, info, warn, error
LOG_LEVEL=debug
STORE_LOG_LEVEL=warn
# Loki Log Path