From dc12ec6dfd177043eaae2f03b9813f5a4bf56c95 Mon Sep 17 00:00:00 2001 From: t0ng7u Date: Tue, 12 Aug 2025 10:45:21 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=AB=20feat(web):=20add=20403=20Forbidd?= =?UTF-8?q?en=20page=20and=20AdminRoute=20guard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add new Forbidden page at /forbidden (`web/src/pages/Forbidden/index.js`) - Use Semi-UI Empty with IllustrationNoAccess (250x250) - Update i18n description to: '您无权访问此页面,请联系管理员~' - Align visual style with existing 404 page - Introduce `AdminRoute` in `web/src/helpers/auth.js` - Use `UserContext`/localStorage; redirect to `/forbidden` when `!user` or `user.role < 10` - Protect console/admin routes with `AdminRoute` and register `/forbidden` in `web/src/App.js` - Update `web/src/i18n/locales/en.json` - Add English translation for the new forbidden message - Remove legacy "没有权限" entry - Lint passes; no runtime errors observed --- web/src/App.js | 27 ++++++++++++--------- web/src/helpers/auth.js | 16 +++++++++++++ web/src/i18n/locales/en.json | 1 + web/src/pages/Forbidden/index.js | 40 ++++++++++++++++++++++++++++++++ web/src/pages/NotFound/index.js | 2 +- 5 files changed, 74 insertions(+), 12 deletions(-) create mode 100644 web/src/pages/Forbidden/index.js diff --git a/web/src/App.js b/web/src/App.js index bf8397ba..8d7e6441 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -21,10 +21,11 @@ import React, { lazy, Suspense } from 'react'; import { Route, Routes, useLocation } from 'react-router-dom'; import Loading from './components/common/ui/Loading.js'; import User from './pages/User'; -import { AuthRedirect, PrivateRoute } from './helpers'; +import { AuthRedirect, PrivateRoute, AdminRoute } from './helpers'; import RegisterForm from './components/auth/RegisterForm.js'; import LoginForm from './components/auth/LoginForm.js'; import NotFound from './pages/NotFound'; +import Forbidden from './pages/Forbidden'; import Setting from './pages/Setting'; import PasswordResetForm from './components/auth/PasswordResetForm.js'; @@ -72,20 +73,24 @@ function App() { } /> + } + /> + - + } /> + - + } /> + - + } /> + - + } /> + } key={location.pathname}> - + } /> ; + } + try { + const user = JSON.parse(raw); + if (user && typeof user.role === 'number' && user.role >= 10) { + return children; + } + } catch (e) { + // ignore + } + return ; +} + export { PrivateRoute }; diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index 3e56aa43..3b4700f6 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -1459,6 +1459,7 @@ "设计与开发由": "Designed & Developed with love by", "演示站点": "Demo Site", "页面未找到,请检查您的浏览器地址是否正确": "Page not found, please check if your browser address is correct", + "您无权访问此页面,请联系管理员": "You do not have permission to access this page. Please contact the administrator.", "New API项目仓库地址:": "New API project repository address: ", "© {{currentYear}}": "© {{currentYear}}", "| 基于": " | Based on ", diff --git a/web/src/pages/Forbidden/index.js b/web/src/pages/Forbidden/index.js new file mode 100644 index 00000000..1c2428e4 --- /dev/null +++ b/web/src/pages/Forbidden/index.js @@ -0,0 +1,40 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React from 'react'; +import { Empty } from '@douyinfe/semi-ui'; +import { IllustrationNoAccess, IllustrationNoAccessDark } from '@douyinfe/semi-illustrations'; +import { useTranslation } from 'react-i18next'; + +const Forbidden = () => { + const { t } = useTranslation(); + return ( +
+ } + darkModeImage={} + description={t('您无权访问此页面,请联系管理员')} + /> +
+ ); +}; + +export default Forbidden; + + diff --git a/web/src/pages/NotFound/index.js b/web/src/pages/NotFound/index.js index be236822..3b263aa5 100644 --- a/web/src/pages/NotFound/index.js +++ b/web/src/pages/NotFound/index.js @@ -25,7 +25,7 @@ import { useTranslation } from 'react-i18next'; const NotFound = () => { const { t } = useTranslation(); return ( -
+
} darkModeImage={}