From f63f06d8796fa8e25d1be5311753691fa947a858 Mon Sep 17 00:00:00 2001 From: samanhappy Date: Tue, 5 Aug 2025 13:45:31 +0800 Subject: [PATCH] feat: Enhance authentication flow by integrating permissions retrieval and updating related services (#256) --- frontend/src/contexts/AuthContext.tsx | 5 +++-- frontend/src/services/configService.ts | 5 +++-- locales/zh.json | 2 +- src/config/index.ts | 10 +++++----- src/controllers/configController.ts | 15 +++++++++++++++ src/controllers/serverController.ts | 3 ++- src/controllers/userController.ts | 6 ++++++ src/services/dataService.ts | 12 ++++++------ 8 files changed, 41 insertions(+), 17 deletions(-) diff --git a/frontend/src/contexts/AuthContext.tsx b/frontend/src/contexts/AuthContext.tsx index 56da07c..b42bd7f 100644 --- a/frontend/src/contexts/AuthContext.tsx +++ b/frontend/src/contexts/AuthContext.tsx @@ -1,7 +1,7 @@ import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react'; import { AuthState } from '../types'; import * as authService from '../services/authService'; -import { shouldSkipAuth } from '../services/configService'; +import { getPublicConfig } from '../services/configService'; // Initial auth state const initialState: AuthState = { @@ -32,7 +32,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => useEffect(() => { const loadUser = async () => { // First check if authentication should be skipped - const skipAuth = await shouldSkipAuth(); + const { skipAuth, permissions } = await getPublicConfig(); if (skipAuth) { // If authentication is disabled, set user as authenticated with a dummy user @@ -42,6 +42,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => user: { username: 'guest', isAdmin: true, + permissions, }, error: null, }); diff --git a/frontend/src/services/configService.ts b/frontend/src/services/configService.ts index 3728f47..bb9fd78 100644 --- a/frontend/src/services/configService.ts +++ b/frontend/src/services/configService.ts @@ -26,6 +26,7 @@ export interface PublicConfigResponse { success: boolean; data?: { skipAuth?: boolean; + permissions?: any; }; message?: string; } @@ -41,7 +42,7 @@ export interface SystemConfigResponse { /** * Get public configuration (skipAuth setting) without authentication */ -export const getPublicConfig = async (): Promise<{ skipAuth: boolean }> => { +export const getPublicConfig = async (): Promise<{ skipAuth: boolean; permissions?: any }> => { try { const basePath = getBasePath(); const response = await fetchWithInterceptors(`${basePath}/public-config`, { @@ -53,7 +54,7 @@ export const getPublicConfig = async (): Promise<{ skipAuth: boolean }> => { if (response.ok) { const data: PublicConfigResponse = await response.json(); - return { skipAuth: data.data?.skipAuth === true }; + return { skipAuth: data.data?.skipAuth === true, permissions: data.data?.permissions || {} }; } return { skipAuth: false }; diff --git a/locales/zh.json b/locales/zh.json index d78c302..4753add 100644 --- a/locales/zh.json +++ b/locales/zh.json @@ -429,7 +429,7 @@ "edit": "编辑用户", "delete": "删除用户", "create": "创建", - "update": "用户", + "update": "更新", "username": "用户名", "password": "密码", "newPassword": "新密码", diff --git a/src/config/index.ts b/src/config/index.ts index 448bd9a..3dc2cfa 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,6 +1,6 @@ import dotenv from 'dotenv'; import fs from 'fs'; -import { McpSettings } from '../types/index.js'; +import { McpSettings, IUser } from '../types/index.js'; import { getConfigFilePath } from '../utils/path.js'; import { getPackageVersion } from '../utils/version.js'; import { getDataService } from '../services/services.js'; @@ -54,14 +54,14 @@ export const loadOriginalSettings = (): McpSettings => { } }; -export const loadSettings = (): McpSettings => { - return dataService.filterSettings!(loadOriginalSettings()); +export const loadSettings = (user?: IUser): McpSettings => { + return dataService.filterSettings!(loadOriginalSettings(), user); }; -export const saveSettings = (settings: McpSettings): boolean => { +export const saveSettings = (settings: McpSettings, user?: IUser): boolean => { const settingsPath = getSettingsPath(); try { - const mergedSettings = dataService.mergeSettings!(loadOriginalSettings(), settings); + const mergedSettings = dataService.mergeSettings!(loadOriginalSettings(), settings, user); fs.writeFileSync(settingsPath, JSON.stringify(mergedSettings, null, 2), 'utf8'); // Update cache after successful save diff --git a/src/controllers/configController.ts b/src/controllers/configController.ts index 442581f..abe6ae3 100644 --- a/src/controllers/configController.ts +++ b/src/controllers/configController.ts @@ -1,6 +1,11 @@ import { Request, Response } from 'express'; import config from '../config/index.js'; import { loadSettings } from '../config/index.js'; +import { getDataService } from '../services/services.js'; +import { DataService } from '../services/dataService.js'; +import { IUser } from '../types/index.js'; + +const dataService: DataService = getDataService(); /** * Get runtime configuration for frontend @@ -38,6 +43,15 @@ export const getPublicConfig = (req: Request, res: Response): void => { try { const settings = loadSettings(); const skipAuth = settings.systemConfig?.routing?.skipAuth || false; + let permissions = {}; + if (skipAuth) { + const user: IUser = { + username: 'guest', + password: '', + isAdmin: true, + }; + permissions = dataService.getPermissions(user); + } res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); res.setHeader('Pragma', 'no-cache'); @@ -47,6 +61,7 @@ export const getPublicConfig = (req: Request, res: Response): void => { success: true, data: { skipAuth, + permissions, }, }); } catch (error) { diff --git a/src/controllers/serverController.ts b/src/controllers/serverController.ts index bbcd335..7743ef0 100644 --- a/src/controllers/serverController.ts +++ b/src/controllers/serverController.ts @@ -506,6 +506,7 @@ export const updateToolDescription = async (req: Request, res: Response): Promis export const updateSystemConfig = (req: Request, res: Response): void => { try { const { routing, install, smartRouting } = req.body; + const currentUser = (req as any).user; if ( (!routing || @@ -675,7 +676,7 @@ export const updateSystemConfig = (req: Request, res: Response): void => { needsSync = (!wasSmartRoutingEnabled && isNowEnabled) || (isNowEnabled && hasConfigChanged); } - if (saveSettings(settings)) { + if (saveSettings(settings, currentUser)) { res.json({ success: true, data: settings.systemConfig, diff --git a/src/controllers/userController.ts b/src/controllers/userController.ts index f2c3a68..bdd87b7 100644 --- a/src/controllers/userController.ts +++ b/src/controllers/userController.ts @@ -9,9 +9,15 @@ import { getUserCount, getAdminCount, } from '../services/userService.js'; +import { loadSettings } from '../config/index.js'; // Admin permission check middleware function const requireAdmin = (req: Request, res: Response): boolean => { + const settings = loadSettings(); + if (settings.systemConfig?.routing?.skipAuth) { + return true; + } + const user = (req as any).user; if (!user || !user.isAdmin) { res.status(403).json({ diff --git a/src/services/dataService.ts b/src/services/dataService.ts index 886b0eb..0905008 100644 --- a/src/services/dataService.ts +++ b/src/services/dataService.ts @@ -2,9 +2,9 @@ import { IUser, McpSettings } from '../types/index.js'; export interface DataService { foo(): void; - filterData(data: any[]): any[]; - filterSettings(settings: McpSettings): McpSettings; - mergeSettings(all: McpSettings, newSettings: McpSettings): McpSettings; + filterData(data: any[], user?: IUser): any[]; + filterSettings(settings: McpSettings, user?: IUser): McpSettings; + mergeSettings(all: McpSettings, newSettings: McpSettings, user?: IUser): McpSettings; getPermissions(user: IUser): string[]; } @@ -13,15 +13,15 @@ export class DataServiceImpl implements DataService { console.log('default implementation'); } - filterData(data: any[]): any[] { + filterData(data: any[], _user?: IUser): any[] { return data; } - filterSettings(settings: McpSettings): McpSettings { + filterSettings(settings: McpSettings, _user?: IUser): McpSettings { return settings; } - mergeSettings(all: McpSettings, newSettings: McpSettings): McpSettings { + mergeSettings(all: McpSettings, newSettings: McpSettings, _user?: IUser): McpSettings { return newSettings; }