fastGPT—nextjs—mongoose—团队管理之团队列表api接口实现

发布于:2025-04-04 ⋅ 阅读:(16) ⋅ 点赞:(0)

 这里的逻辑是一个人可以在多个团队中,但在每个团队的角色有可能是不一样的,当一个人同时存在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 jwt
  async function authCookieToken(cookie?: string, token?: string) {
    // 获取 cookie
    const cookies = Cookie.parse(cookie || '');
    const cookieToken = token || cookies[TokenName];

    if (!cookieToken) {
      return Promise.reject(ERROR_ENUM.unAuthorization);
    }

    return await authJWT(cookieToken);
  }
  // from authorization get apikey
  async function parseAuthorization(authorization?: string) {
    if (!authorization) {
      return Promise.reject(ERROR_ENUM.unAuthorization);
    }

    // Bearer fastgpt-xxxx-appId
    const auth = authorization.split(' ')[1];
    if (!auth) {
      return Promise.reject(ERROR_ENUM.unAuthorization);
    }

    const { apikey, appId: authorizationAppid = '' } = await (async () => {
      const arr = auth.split('-');
      // abandon
      if (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 apikey
    const { teamId, tmbId, appId: apiKeyAppId = '', sourceName } = await authOpenApiKey({ apikey });

    return {
      uid: '',
      teamId,
      tmbId,
      apikey,
      appId: apiKeyAppId || authorizationAppid,
      sourceName
    };
  }
  // root user
  async 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 authorization
        const 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 user
        return {
          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


网站公告

今日签到

点亮在社区的每一天
去签到