mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-29 09:44:47 +00:00
perf: send code
This commit is contained in:
2
client/.gitignore
vendored
2
client/.gitignore
vendored
@@ -29,4 +29,4 @@ platform.json
|
|||||||
testApi/
|
testApi/
|
||||||
local/
|
local/
|
||||||
.husky/
|
.husky/
|
||||||
data/*.local
|
data/*.local.*
|
@@ -88,7 +88,7 @@ const defaultVectorModels = [
|
|||||||
export async function getInitConfig() {
|
export async function getInitConfig() {
|
||||||
try {
|
try {
|
||||||
const filename =
|
const filename =
|
||||||
process.env.NODE_ENV === 'development' ? 'data/config.json.local' : '/app/data/config.json';
|
process.env.NODE_ENV === 'development' ? 'data/config.local.json' : '/app/data/config.json';
|
||||||
const res = JSON.parse(readFileSync(filename, 'utf-8'));
|
const res = JSON.parse(readFileSync(filename, 'utf-8'));
|
||||||
console.log(res);
|
console.log(res);
|
||||||
|
|
||||||
@@ -97,6 +97,7 @@ export async function getInitConfig() {
|
|||||||
global.chatModels = res.ChatModels || defaultChatModels;
|
global.chatModels = res.ChatModels || defaultChatModels;
|
||||||
global.qaModels = res.QAModels || defaultQAModels;
|
global.qaModels = res.QAModels || defaultQAModels;
|
||||||
global.vectorModels = res.VectorModels || defaultVectorModels;
|
global.vectorModels = res.VectorModels || defaultVectorModels;
|
||||||
|
global.systemPlugins = res.plugins || {};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setDefaultData();
|
setDefaultData();
|
||||||
console.log('get init config error, set default', error);
|
console.log('get init config error, set default', error);
|
||||||
@@ -109,4 +110,5 @@ export function setDefaultData() {
|
|||||||
global.chatModels = defaultChatModels;
|
global.chatModels = defaultChatModels;
|
||||||
global.qaModels = defaultQAModels;
|
global.qaModels = defaultQAModels;
|
||||||
global.vectorModels = defaultVectorModels;
|
global.vectorModels = defaultVectorModels;
|
||||||
|
global.systemPlugins = {};
|
||||||
}
|
}
|
||||||
|
@@ -2,10 +2,10 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@/service/response';
|
import { jsonRes } from '@/service/response';
|
||||||
import { User } from '@/service/models/user';
|
import { User } from '@/service/models/user';
|
||||||
import { AuthCode } from '@/service/models/authCode';
|
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import { generateToken, setCookie } from '@/service/utils/tools';
|
import { generateToken, setCookie } from '@/service/utils/tools';
|
||||||
import { UserAuthTypeEnum } from '@/constants/common';
|
import { UserAuthTypeEnum } from '@/constants/common';
|
||||||
|
import { authCode } from '@/service/api/plugins';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
@@ -18,17 +18,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
await connectToDatabase();
|
await connectToDatabase();
|
||||||
|
|
||||||
// 验证码校验
|
// 验证码校验
|
||||||
const authCode = await AuthCode.findOne({
|
await authCode({
|
||||||
username,
|
username,
|
||||||
code,
|
|
||||||
type: UserAuthTypeEnum.register,
|
type: UserAuthTypeEnum.register,
|
||||||
expiredTime: { $gte: Date.now() }
|
code
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!authCode) {
|
|
||||||
throw new Error('验证码错误');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重名校验
|
// 重名校验
|
||||||
const authRepeat = await User.findOne({
|
const authRepeat = await User.findOne({
|
||||||
username
|
username
|
||||||
@@ -51,11 +46,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
throw new Error('获取用户信息异常');
|
throw new Error('获取用户信息异常');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除验证码记录
|
|
||||||
await AuthCode.deleteMany({
|
|
||||||
username
|
|
||||||
});
|
|
||||||
|
|
||||||
const token = generateToken(user._id);
|
const token = generateToken(user._id);
|
||||||
setCookie(res, token);
|
setCookie(res, token);
|
||||||
|
|
||||||
|
@@ -2,10 +2,10 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@/service/response';
|
import { jsonRes } from '@/service/response';
|
||||||
import { User } from '@/service/models/user';
|
import { User } from '@/service/models/user';
|
||||||
import { AuthCode } from '@/service/models/authCode';
|
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
import { UserAuthTypeEnum } from '@/constants/common';
|
import { UserAuthTypeEnum } from '@/constants/common';
|
||||||
import { generateToken, setCookie } from '@/service/utils/tools';
|
import { generateToken, setCookie } from '@/service/utils/tools';
|
||||||
|
import { authCode } from '@/service/api/plugins';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
try {
|
try {
|
||||||
@@ -18,11 +18,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
|
|||||||
await connectToDatabase();
|
await connectToDatabase();
|
||||||
|
|
||||||
// 验证码校验
|
// 验证码校验
|
||||||
const authCode = await AuthCode.findOne({
|
await authCode({
|
||||||
username,
|
username,
|
||||||
code,
|
code,
|
||||||
type: UserAuthTypeEnum.findPassword,
|
type: UserAuthTypeEnum.findPassword
|
||||||
expiredTime: { $gte: Date.now() }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!authCode) {
|
if (!authCode) {
|
||||||
|
@@ -1,13 +1,9 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { jsonRes } from '@/service/response';
|
import { jsonRes } from '@/service/response';
|
||||||
import { AuthCode } from '@/service/models/authCode';
|
|
||||||
import { connectToDatabase } from '@/service/mongo';
|
|
||||||
import { sendPhoneCode, sendEmailCode } from '@/service/utils/sendNote';
|
|
||||||
import { UserAuthTypeEnum } from '@/constants/common';
|
import { UserAuthTypeEnum } from '@/constants/common';
|
||||||
import { customAlphabet } from 'nanoid';
|
|
||||||
const nanoid = customAlphabet('123456789', 6);
|
|
||||||
import { authGoogleToken } from '@/utils/plugin/google';
|
import { authGoogleToken } from '@/utils/plugin/google';
|
||||||
import requestIp from 'request-ip';
|
import requestIp from 'request-ip';
|
||||||
|
import { sendCode } from '@/service/api/plugins';
|
||||||
|
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
try {
|
try {
|
||||||
@@ -29,40 +25,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||||||
remoteip: requestIp.getClientIp(req) || undefined
|
remoteip: requestIp.getClientIp(req) || undefined
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await connectToDatabase();
|
|
||||||
|
|
||||||
// register switch
|
// register switch
|
||||||
if (type === UserAuthTypeEnum.register && !global.feConfigs?.show_register) {
|
if (type === UserAuthTypeEnum.register && !global.feConfigs?.show_register) {
|
||||||
throw new Error('Register is closed');
|
throw new Error('Register is closed');
|
||||||
}
|
}
|
||||||
|
|
||||||
const code = nanoid();
|
await sendCode({
|
||||||
|
|
||||||
// 判断 1 分钟内是否有重复数据
|
|
||||||
const authCode = await AuthCode.findOne({
|
|
||||||
username,
|
username,
|
||||||
type,
|
type
|
||||||
expiredTime: { $gte: Date.now() + 4 * 60 * 1000 } // 如果有一个记录的过期时间,大于当前+4分钟,说明距离上次发送还没到1分钟。(因为默认创建时,过期时间是未来5分钟)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (authCode) {
|
|
||||||
throw new Error('请勿频繁获取验证码');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建 auth 记录
|
|
||||||
await AuthCode.create({
|
|
||||||
username,
|
|
||||||
type,
|
|
||||||
code
|
|
||||||
});
|
|
||||||
|
|
||||||
if (username.includes('@')) {
|
|
||||||
await sendEmailCode(username, code, type);
|
|
||||||
} else {
|
|
||||||
// 发送验证码
|
|
||||||
await sendPhoneCode(username, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonRes(res, {
|
jsonRes(res, {
|
||||||
message: '发送验证码成功'
|
message: '发送验证码成功'
|
||||||
});
|
});
|
||||||
|
11
client/src/service/api/plugins.d.ts
vendored
Normal file
11
client/src/service/api/plugins.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { UserAuthTypeEnum } from '../../constants/common';
|
||||||
|
|
||||||
|
export type SendCodeBody = {
|
||||||
|
username: string;
|
||||||
|
type: `${UserAuthTypeEnum}`;
|
||||||
|
};
|
||||||
|
export type AuthCodeBody = {
|
||||||
|
username: string;
|
||||||
|
type: `${UserAuthTypeEnum}`;
|
||||||
|
code: string;
|
||||||
|
};
|
5
client/src/service/api/plugins.ts
Normal file
5
client/src/service/api/plugins.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { POST } from './request';
|
||||||
|
import type { SendCodeBody, AuthCodeBody } from './plugins.d';
|
||||||
|
|
||||||
|
export const sendCode = (data: SendCodeBody) => POST(global.systemPlugins.authCode?.sendUrl, data);
|
||||||
|
export const authCode = (data: AuthCodeBody) => POST(global.systemPlugins.authCode?.authUrl, data);
|
129
client/src/service/api/request.ts
Normal file
129
client/src/service/api/request.ts
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import axios, { Method, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
|
||||||
|
import { clearToken, getToken } from '@/utils/user';
|
||||||
|
import { TOKEN_ERROR_CODE } from '@/service/errorCode';
|
||||||
|
|
||||||
|
interface ConfigType {
|
||||||
|
headers?: { [key: string]: string };
|
||||||
|
hold?: boolean;
|
||||||
|
timeout?: number;
|
||||||
|
}
|
||||||
|
interface ResponseDataType {
|
||||||
|
code: number;
|
||||||
|
message: string;
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求开始
|
||||||
|
*/
|
||||||
|
function requestStart(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig {
|
||||||
|
if (config.headers) {
|
||||||
|
// config.headers.token = getToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求成功,检查请求头
|
||||||
|
*/
|
||||||
|
function responseSuccess(response: AxiosResponse<ResponseDataType>) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 响应数据检查
|
||||||
|
*/
|
||||||
|
function checkRes(data: ResponseDataType) {
|
||||||
|
if (data === undefined) {
|
||||||
|
console.log('error->', data, 'data is empty');
|
||||||
|
return Promise.reject('服务器异常');
|
||||||
|
} else if (data.code < 200 || data.code >= 400) {
|
||||||
|
return Promise.reject(data);
|
||||||
|
}
|
||||||
|
return data.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 响应错误
|
||||||
|
*/
|
||||||
|
function responseError(err: any) {
|
||||||
|
if (!err) {
|
||||||
|
return Promise.reject({ message: '未知错误' });
|
||||||
|
}
|
||||||
|
if (typeof err === 'string') {
|
||||||
|
return Promise.reject({ message: err });
|
||||||
|
}
|
||||||
|
// 有报错响应
|
||||||
|
if (err?.code in TOKEN_ERROR_CODE) {
|
||||||
|
clearToken();
|
||||||
|
window.location.replace(
|
||||||
|
`/login?lastRoute=${encodeURIComponent(location.pathname + location.search)}`
|
||||||
|
);
|
||||||
|
return Promise.reject({ message: 'token过期,重新登录' });
|
||||||
|
}
|
||||||
|
if (err?.response?.data) {
|
||||||
|
return Promise.reject(err?.response?.data);
|
||||||
|
}
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 创建请求实例 */
|
||||||
|
const instance = axios.create({
|
||||||
|
timeout: 60000, // 超时时间
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* 请求拦截 */
|
||||||
|
instance.interceptors.request.use(requestStart, (err) => Promise.reject(err));
|
||||||
|
/* 响应拦截 */
|
||||||
|
instance.interceptors.response.use(responseSuccess, (err) => Promise.reject(err));
|
||||||
|
|
||||||
|
function request(url: string, data: any, config: ConfigType, method: Method): any {
|
||||||
|
/* 去空 */
|
||||||
|
for (const key in data) {
|
||||||
|
if (data[key] === null || data[key] === undefined) {
|
||||||
|
delete data[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance
|
||||||
|
.request({
|
||||||
|
baseURL: '/api',
|
||||||
|
url,
|
||||||
|
method,
|
||||||
|
data: ['POST', 'PUT'].includes(method) ? data : null,
|
||||||
|
params: !['POST', 'PUT'].includes(method) ? data : null,
|
||||||
|
...config // 用户自定义配置,可以覆盖前面的配置
|
||||||
|
})
|
||||||
|
.then((res) => checkRes(res.data))
|
||||||
|
.catch((err) => responseError(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* api请求方式
|
||||||
|
* @param {String} url
|
||||||
|
* @param {Any} params
|
||||||
|
* @param {Object} config
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function GET<T>(url?: string, params = {}, config: ConfigType = {}): Promise<T> {
|
||||||
|
if (!url) return Promise.reject('no url');
|
||||||
|
return request(url, params, config, 'GET');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function POST<T>(url?: string, data = {}, config: ConfigType = {}): Promise<T> {
|
||||||
|
if (!url) return Promise.reject('no url');
|
||||||
|
return request(url, data, config, 'POST');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PUT<T>(url?: string, data = {}, config: ConfigType = {}): Promise<T> {
|
||||||
|
if (!url) return Promise.reject('no url');
|
||||||
|
return request(url, data, config, 'PUT');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DELETE<T>(url?: string, data = {}, config: ConfigType = {}): Promise<T> {
|
||||||
|
if (!url) return Promise.reject('no url');
|
||||||
|
return request(url, data, config, 'DELETE');
|
||||||
|
}
|
@@ -1,26 +0,0 @@
|
|||||||
import { Schema, model, models, Model } from 'mongoose';
|
|
||||||
import { AuthCodeSchema as AuthCodeType } from '@/types/mongoSchema';
|
|
||||||
|
|
||||||
const AuthCodeSchema = new Schema({
|
|
||||||
username: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
code: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
length: 6
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
enum: ['register', 'findPassword'],
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
expiredTime: {
|
|
||||||
type: Number,
|
|
||||||
default: () => Date.now() + 5 * 60 * 1000
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AuthCode: Model<AuthCodeType> =
|
|
||||||
models['auth_code'] || model('auth_code', AuthCodeSchema);
|
|
@@ -19,11 +19,6 @@ export async function connectToDatabase(): Promise<void> {
|
|||||||
// init global data
|
// init global data
|
||||||
global.qaQueueLen = 0;
|
global.qaQueueLen = 0;
|
||||||
global.vectorQueueLen = 0;
|
global.vectorQueueLen = 0;
|
||||||
global.systemEnv = {
|
|
||||||
vectorMaxProcess: 10,
|
|
||||||
qaMaxProcess: 10,
|
|
||||||
pgIvfflatProbe: 10
|
|
||||||
};
|
|
||||||
global.sendInformQueue = [];
|
global.sendInformQueue = [];
|
||||||
global.sendInformQueueLen = 0;
|
global.sendInformQueueLen = 0;
|
||||||
// proxy obj
|
// proxy obj
|
||||||
@@ -116,7 +111,6 @@ async function initPg() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export * from './models/authCode';
|
|
||||||
export * from './models/chat';
|
export * from './models/chat';
|
||||||
export * from './models/app';
|
export * from './models/app';
|
||||||
export * from './models/user';
|
export * from './models/user';
|
||||||
|
16
client/src/types/index.d.ts
vendored
16
client/src/types/index.d.ts
vendored
@@ -31,13 +31,15 @@ export type SystemEnvType = {
|
|||||||
qaMaxProcess: number;
|
qaMaxProcess: number;
|
||||||
pgIvfflatProbe: number;
|
pgIvfflatProbe: number;
|
||||||
};
|
};
|
||||||
type PluginItemType = {
|
|
||||||
url: string;
|
|
||||||
auth: string;
|
|
||||||
};
|
|
||||||
export type PluginType = {
|
export type PluginType = {
|
||||||
authCode?: PluginItemType;
|
authCode?: {
|
||||||
moderationsCheck?: PluginItemType;
|
sendUrl: string;
|
||||||
|
authUrl: string;
|
||||||
|
};
|
||||||
|
moderationsCheck?: {
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@@ -52,7 +54,7 @@ declare global {
|
|||||||
|
|
||||||
var feConfigs: FeConfigsType;
|
var feConfigs: FeConfigsType;
|
||||||
var systemEnv: SystemEnvType;
|
var systemEnv: SystemEnvType;
|
||||||
var;
|
var systemPlugins: PluginType;
|
||||||
var chatModels: ChatModelItemType[];
|
var chatModels: ChatModelItemType[];
|
||||||
var qaModels: QAModelItemType[];
|
var qaModels: QAModelItemType[];
|
||||||
var vectorModels: VectorModelItemType[];
|
var vectorModels: VectorModelItemType[];
|
||||||
|
Reference in New Issue
Block a user