From 69dc927a5a73de2860b83e9787fd0584ebf898b8 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Wed, 11 Dec 2024 15:46:21 +0800 Subject: [PATCH] feat: login limit (#3369) * feat: login limit * feat: env template * fix: ts --- packages/global/common/error/errorCode.ts | 2 +- .../service/support/tmpData/controller.ts | 7 +- packages/web/i18n/en/common.json | 1 + packages/web/i18n/zh-CN/common.json | 5 +- packages/web/i18n/zh-Hant/common.json | 1 + projects/app/.env.template | 2 + .../src/pages/api/core/dataset/searchTest.ts | 2 +- .../support/user/account/loginByPassword.ts | 114 ++++++++---------- .../src/pages/api/v1/audio/transcriptions.ts | 2 +- 9 files changed, 65 insertions(+), 71 deletions(-) diff --git a/packages/global/common/error/errorCode.ts b/packages/global/common/error/errorCode.ts index a11bc974b..478694742 100644 --- a/packages/global/common/error/errorCode.ts +++ b/packages/global/common/error/errorCode.ts @@ -72,7 +72,7 @@ export const ERROR_RESPONSE: Record< [ERROR_ENUM.tooManyRequest]: { code: 429, statusText: ERROR_ENUM.tooManyRequest, - message: 'Too many request', + message: i18nT('common:error.too_many_request'), data: null }, [ERROR_ENUM.insufficientQuota]: { diff --git a/packages/service/support/tmpData/controller.ts b/packages/service/support/tmpData/controller.ts index 09558837d..da499195c 100644 --- a/packages/service/support/tmpData/controller.ts +++ b/packages/service/support/tmpData/controller.ts @@ -24,7 +24,7 @@ export async function getTmpData({ }).lean()) as TmpDataSchema> | null; } -export async function setTmpData({ +export function setTmpData({ type, metadata, data @@ -33,7 +33,7 @@ export async function setTmpData({ metadata: TmpDataMetadata; data: TmpDataType; }) { - return await MongoTmpData.updateOne( + return MongoTmpData.updateOne( { dataId: getDataId(type, metadata) }, @@ -43,7 +43,8 @@ export async function setTmpData({ expireAt: addMilliseconds(Date.now(), TmpDataExpireTime[type]) }, { - upsert: true + upsert: true, + new: true } ); } diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index 25119661b..427fdb794 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -874,6 +874,7 @@ "error.fileNotFound": "File not found~", "error.inheritPermissionError": "Inherit permission Error", "error.missingParams": "Insufficient parameters", + "error.too_many_request": "Too many request", "error.upload_file_error_filename": "{{name}} Upload Failed", "error.username_empty": "Account cannot be empty", "extraction_results": "Extraction Results", diff --git a/packages/web/i18n/zh-CN/common.json b/packages/web/i18n/zh-CN/common.json index 28e0bcd10..834abc46d 100644 --- a/packages/web/i18n/zh-CN/common.json +++ b/packages/web/i18n/zh-CN/common.json @@ -873,6 +873,7 @@ "error.fileNotFound": "文件找不到了~", "error.inheritPermissionError": "权限继承错误", "error.missingParams": "参数缺失", + "error.too_many_request": "请求太频繁了,请稍后重试", "error.upload_file_error_filename": "{{name}} 上传失败", "error.username_empty": "账号不能为空", "extraction_results": "提取结果", @@ -1179,7 +1180,6 @@ "user.password_message": "密码最少 4 位最多 60 位", "user.team.Balance": "团队余额", "user.team.Check Team": "切换", - "user.team.Invite Member": "邀请成员", "user.team.Invite Member Tips": "对方可查阅或使用团队内的其他资源", "user.team.Leave Team": "离开团队", @@ -1192,13 +1192,10 @@ "user.team.Processing invitations Tips": "你有 {{amount}} 个需要处理的团队邀请", "user.team.Remove Member Confirm Tip": "确认将 {{username}} 移出团队?", "user.team.Select Team": "团队选择", - "user.team.Switch Team Failed": "切换团队异常", "user.team.Tags Async": "保存", - "user.team.Team Tags Async": "标签同步", "user.team.Team Tags Async Success": "链接报错成功,标签信息更新", - "user.team.invite.Accept Confirm": "确认加入该团队?", "user.team.invite.Accepted": "已加入团队", "user.team.invite.Deal Width Footer Tip": "处理完会自动关闭噢~", diff --git a/packages/web/i18n/zh-Hant/common.json b/packages/web/i18n/zh-Hant/common.json index 99a876d01..ac1618ec9 100644 --- a/packages/web/i18n/zh-Hant/common.json +++ b/packages/web/i18n/zh-Hant/common.json @@ -873,6 +873,7 @@ "error.fileNotFound": "找不到檔案", "error.inheritPermissionError": "繼承權限錯誤", "error.missingParams": "參數不足", + "error.too_many_request": "請求太頻繁了,請稍後重試", "error.upload_file_error_filename": "{{name}} 上傳失敗", "error.username_empty": "帳號不能為空", "extraction_results": "提取結果", diff --git a/projects/app/.env.template b/projects/app/.env.template index 5e043417d..9e24af247 100644 --- a/projects/app/.env.template +++ b/projects/app/.env.template @@ -43,6 +43,8 @@ LOG_LEVEL=debug STORE_LOG_LEVEL=warn # 安全配置 +# 启动 IP 限流(true),部分接口增加了 ip 限流策略,防止非正常请求操作。 +USE_IP_LIMIT=false # 工作流最大运行次数,避免极端的死循环情况 WORKFLOW_MAX_RUN_TIMES=500 # 循环最大运行次数,避免极端的死循环情况 diff --git a/projects/app/src/pages/api/core/dataset/searchTest.ts b/projects/app/src/pages/api/core/dataset/searchTest.ts index 559aaa51c..f43fed65f 100644 --- a/projects/app/src/pages/api/core/dataset/searchTest.ts +++ b/projects/app/src/pages/api/core/dataset/searchTest.ts @@ -99,4 +99,4 @@ async function handler(req: NextApiRequest) { }; } -export default NextAPI(useReqFrequencyLimit(1, 2), handler); +export default NextAPI(useReqFrequencyLimit(1, 15), handler); diff --git a/projects/app/src/pages/api/support/user/account/loginByPassword.ts b/projects/app/src/pages/api/support/user/account/loginByPassword.ts index 5a165b572..cc35b74c7 100644 --- a/projects/app/src/pages/api/support/user/account/loginByPassword.ts +++ b/projects/app/src/pages/api/support/user/account/loginByPassword.ts @@ -1,71 +1,63 @@ import type { NextApiRequest, NextApiResponse } from 'next'; -import { jsonRes } from '@fastgpt/service/common/response'; import { MongoUser } from '@fastgpt/service/support/user/schema'; import { createJWT, setCookie } from '@fastgpt/service/support/permission/controller'; -import { connectToDatabase } from '@/service/mongo'; import { getUserDetail } from '@fastgpt/service/support/user/controller'; import type { PostLoginProps } from '@fastgpt/global/support/user/api.d'; import { UserStatusEnum } from '@fastgpt/global/support/user/constant'; +import { NextAPI } from '@/service/middleware/entry'; +import { useReqFrequencyLimit } from '@fastgpt/service/common/middle/reqFrequencyLimit'; -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - try { - await connectToDatabase(); - const { username, password } = req.body as PostLoginProps; +async function handler(req: NextApiRequest, res: NextApiResponse) { + const { username, password } = req.body as PostLoginProps; - if (!username || !password) { - throw new Error('缺少参数'); - } - - // 检测用户是否存在 - const authCert = await MongoUser.findOne( - { - username - }, - 'status' - ); - if (!authCert) { - throw new Error('用户未注册'); - } - - if (authCert.status === UserStatusEnum.forbidden) { - throw new Error('账号已停用,无法登录'); - } - - const user = await MongoUser.findOne({ - username, - password - }); - - if (!user) { - throw new Error('密码错误'); - } - - const userDetail = await getUserDetail({ - tmbId: user?.lastLoginTmbId, - userId: user._id - }); - - MongoUser.findByIdAndUpdate(user._id, { - lastLoginTmbId: userDetail.team.tmbId - }); - - const token = createJWT({ - ...userDetail, - isRoot: username === 'root' - }); - - setCookie(res, token); - - jsonRes(res, { - data: { - user: userDetail, - token - } - }); - } catch (err) { - jsonRes(res, { - code: 500, - error: err - }); + if (!username || !password) { + throw new Error('缺少参数'); } + + // 检测用户是否存在 + const authCert = await MongoUser.findOne( + { + username + }, + 'status' + ); + if (!authCert) { + throw new Error('用户未注册'); + } + + if (authCert.status === UserStatusEnum.forbidden) { + throw new Error('账号已停用,无法登录'); + } + + const user = await MongoUser.findOne({ + username, + password + }); + + if (!user) { + throw new Error('密码错误'); + } + + const userDetail = await getUserDetail({ + tmbId: user?.lastLoginTmbId, + userId: user._id + }); + + MongoUser.findByIdAndUpdate(user._id, { + lastLoginTmbId: userDetail.team.tmbId + }); + + const token = createJWT({ + ...userDetail, + isRoot: username === 'root' + }); + + setCookie(res, token); + + return { + user: userDetail, + token + }; } + +export default NextAPI(useReqFrequencyLimit(120, 10), handler); diff --git a/projects/app/src/pages/api/v1/audio/transcriptions.ts b/projects/app/src/pages/api/v1/audio/transcriptions.ts index 29d3fcf66..ac51e36e0 100644 --- a/projects/app/src/pages/api/v1/audio/transcriptions.ts +++ b/projects/app/src/pages/api/v1/audio/transcriptions.ts @@ -89,7 +89,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { removeFilesByPaths(filePaths); } -export default NextAPI(useReqFrequencyLimit(1, 2), handler); +export default NextAPI(useReqFrequencyLimit(1, 1), handler); export const config = { api: {