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

这里的逻辑是一个人可以在多个团队中,但在每个团队的角色有可能是不一样的,当一个人同时存在2个或者多个团队中时,下拉列表中会有多个团队详情,切换团队会查询不同的成员和部门。

团队列表查询api实现代码:

javascript 复制代码
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接口代码:

javascript 复制代码
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解析验证的,开源代码里面有个文件有以下代码主要是用来解析验证的:

javascript 复制代码
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 向量库都得有

XML 复制代码
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@[email protected]: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
相关推荐
腾讯TNTWeb前端团队4 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰8 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪8 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪8 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy9 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom9 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom9 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom9 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom10 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom10 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试