🚫 feat(web): add 403 Forbidden page and AdminRoute guard

- 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
This commit is contained in:
t0ng7u
2025-08-12 10:45:21 +08:00
parent 6eec8851eb
commit dc12ec6dfd
5 changed files with 74 additions and 12 deletions

View File

@@ -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() {
</Suspense>
}
/>
<Route
path='/forbidden'
element={<Forbidden />}
/>
<Route
path='/console/models'
element={
<PrivateRoute>
<AdminRoute>
<ModelPage />
</PrivateRoute>
</AdminRoute>
}
/>
<Route
path='/console/channel'
element={
<PrivateRoute>
<AdminRoute>
<Channel />
</PrivateRoute>
</AdminRoute>
}
/>
<Route
@@ -107,17 +112,17 @@ function App() {
<Route
path='/console/redemption'
element={
<PrivateRoute>
<AdminRoute>
<Redemption />
</PrivateRoute>
</AdminRoute>
}
/>
<Route
path='/console/user'
element={
<PrivateRoute>
<AdminRoute>
<User />
</PrivateRoute>
</AdminRoute>
}
/>
<Route
@@ -183,11 +188,11 @@ function App() {
<Route
path='/console/setting'
element={
<PrivateRoute>
<AdminRoute>
<Suspense fallback={<Loading></Loading>} key={location.pathname}>
<Setting />
</Suspense>
</PrivateRoute>
</AdminRoute>
}
/>
<Route