Sfoglia il codice sorgente

Merge remote-tracking branch 'origin/master' into dev/6.2.x

Yuki Takei 2 anni fa
parent
commit
9755eda5ae
30 ha cambiato i file con 144 aggiunte e 8 eliminazioni
  1. 9 1
      CHANGELOG.md
  2. 3 0
      apps/app/public/static/locales/en_US/admin.json
  3. 3 0
      apps/app/public/static/locales/ja_JP/admin.json
  4. 3 0
      apps/app/public/static/locales/zh_CN/admin.json
  5. 17 0
      apps/app/src/components/Admin/ForbiddenPage.tsx
  6. 1 1
      apps/app/src/components/LoginForm.tsx
  7. 5 0
      apps/app/src/pages/admin/[...path].page.tsx
  8. 5 1
      apps/app/src/pages/admin/app.page.tsx
  9. 5 1
      apps/app/src/pages/admin/audit-log.page.tsx
  10. 4 0
      apps/app/src/pages/admin/customize.page.tsx
  11. 5 0
      apps/app/src/pages/admin/data-transfer.page.tsx
  12. 5 0
      apps/app/src/pages/admin/export.page.tsx
  13. 4 0
      apps/app/src/pages/admin/global-notification/[globalNotificationId].page.tsx
  14. 4 0
      apps/app/src/pages/admin/global-notification/new.page.tsx
  15. 5 0
      apps/app/src/pages/admin/importer.page.tsx
  16. 9 1
      apps/app/src/pages/admin/index.page.tsx
  17. 4 0
      apps/app/src/pages/admin/markdown.page.tsx
  18. 5 0
      apps/app/src/pages/admin/notification.page.tsx
  19. 5 0
      apps/app/src/pages/admin/plugins.page.tsx
  20. 5 0
      apps/app/src/pages/admin/search.page.tsx
  21. 5 0
      apps/app/src/pages/admin/security.page.tsx
  22. 5 1
      apps/app/src/pages/admin/slack-integration-legacy.page.tsx
  23. 5 0
      apps/app/src/pages/admin/slack-integration.page.tsx
  24. 5 0
      apps/app/src/pages/admin/user-group-detail/[userGroupId].page.tsx
  25. 5 0
      apps/app/src/pages/admin/user-groups.page.tsx
  26. 4 0
      apps/app/src/pages/admin/users/external-accounts.page.tsx
  27. 4 1
      apps/app/src/pages/admin/users/index.page.tsx
  28. 1 0
      apps/app/src/pages/utils/commons.ts
  29. 0 1
      apps/app/src/server/middlewares/admin-required.js
  30. 4 0
      apps/app/src/utils/admin-page-util.ts

+ 9 - 1
CHANGELOG.md

@@ -1,9 +1,17 @@
 # Changelog
 
-## [Unreleased](https://github.com/weseek/growi/compare/v6.1.10...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v6.1.11...HEAD)
 
 *Please do not manually update this file. We've automated the process.*
 
+## [v6.1.11](https://github.com/weseek/growi/compare/v6.1.10...v6.1.11) - 2023-08-07
+
+### 🐛 Bug Fixes
+
+- fix: Admin page permission when the user transit with next-routing (#7908) @WNomunomu
+- fix: Transitioning to a non-existent page under "/me" results in a 500 error (#7946) @miya
+- fix: Auto-scroll search result content 2 (#7943) @yuki-takei
+
 ## [v6.1.10](https://github.com/weseek/growi/compare/v6.1.9...v6.1.10) - 2023-08-01
 
 ### 🐛 Bug Fixes

+ 3 - 0
apps/app/public/static/locales/en_US/admin.json

@@ -1060,5 +1060,8 @@
     "activate_plugin_success": "Succeeded to activating {{pluginName}}",
     "deactivate_plugin_success": "Succeeded to deactivate {{pluginName}}",
     "remove_plugin_success": "Succeeded to removing {{pluginName}}"
+  },
+  "forbidden_page": {
+    "do_not_have_admin_permission": "Users without administrative rights cannot access the administration screen."
   }
 }

+ 3 - 0
apps/app/public/static/locales/ja_JP/admin.json

@@ -1068,5 +1068,8 @@
     "activate_plugin_success": "{{pluginName}}を有効化しました",
     "deactivate_plugin_success": "{{pluginName}}を無効化しました",
     "remove_plugin_success": "{{pluginName}}を削除しました"
+  },
+  "forbidden_page": {
+    "do_not_have_admin_permission": "管理者権限のないユーザーでは管理画面にはアクセスできません。"
   }
 }

+ 3 - 0
apps/app/public/static/locales/zh_CN/admin.json

@@ -1068,5 +1068,8 @@
     "activate_plugin_success": "Succeeded to activating {{pluginName}}",
     "deactivate_plugin_success": "Succeeded to deactivate {{pluginName}}",
     "remove_plugin_success": "Succeeded to removing {{pluginName}}"
+  },
+  "forbidden_page": {
+    "do_not_have_admin_permission": "没有管理权限的用户无法访问管理屏幕。"
   }
 }

+ 17 - 0
apps/app/src/components/Admin/ForbiddenPage.tsx

@@ -0,0 +1,17 @@
+import React from 'react';
+
+import DefaultErrorPage from 'next/error';
+import { useTranslation } from 'react-i18next';
+
+
+export const ForbiddenPage = (): JSX.Element => {
+  const { t } = useTranslation('admin');
+
+  const errorMessage = t('forbidden_page.do_not_have_admin_permission');
+
+  return (
+    <>
+      <DefaultErrorPage statusCode={403} title={errorMessage} />
+    </>
+  );
+};

+ 1 - 1
apps/app/src/components/LoginForm.tsx

@@ -18,7 +18,6 @@ import { CompleteUserRegistration } from './CompleteUserRegistration';
 
 import styles from './LoginForm.module.scss';
 
-
 type LoginFormProps = {
   username?: string,
   name?: string,
@@ -335,6 +334,7 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
       resetRegisterErrors();
 
       const { redirectTo } = res.data;
+
       if (redirectTo != null) {
         router.push(redirectTo);
       }

+ 5 - 0
apps/app/src/pages/admin/[...path].page.tsx

@@ -11,12 +11,17 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const AdminNotFoundPage = dynamic(() => import('~/components/Admin/NotFoundPage').then(mod => mod.AdminNotFoundPage), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 const AdminAppPage: NextPage<CommonProps> = (props) => {
   useIsMaintenanceMode(props.isMaintenanceMode);
   useCurrentUser(props.currentUser ?? null);
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
   return (
     <AdminLayout>
       <AdminNotFoundPage />

+ 5 - 1
apps/app/src/pages/admin/app.page.tsx

@@ -7,7 +7,6 @@ import dynamic from 'next/dynamic';
 import Head from 'next/head';
 import { Container, Provider } from 'unstated';
 
-
 import AdminAppContainer from '~/client/services/AdminAppContainer';
 import { CommonProps, generateCustomTitle } from '~/pages/utils/commons';
 import { useCurrentUser } from '~/stores/context';
@@ -18,6 +17,7 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const AppSettingsPageContents = dynamic(() => import('~/components/Admin/App/AppSettingsPageContents'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 const AdminAppPage: NextPage<CommonProps> = (props) => {
@@ -34,6 +34,10 @@ const AdminAppPage: NextPage<CommonProps> = (props) => {
 
   const title = generateCustomTitle(props, t('headers.app_settings'));
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
   return (
     <Provider inject={[...injectableContainers]}>
       <AdminLayout componentTitle={title}>

+ 5 - 1
apps/app/src/pages/admin/audit-log.page.tsx

@@ -13,8 +13,8 @@ import { useCurrentUser, useAuditLogEnabled, useAuditLogAvailableActions } from
 import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
-
 const AuditLogManagement = dynamic(() => import('~/components/Admin/AuditLogManagement').then(mod => mod.AuditLogManagement), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 type Props = CommonProps & {
@@ -32,6 +32,10 @@ const AdminAuditLogPage: NextPage<Props> = (props) => {
   const title = t('audit_log_management.audit_log');
   const headTitle = generateCustomTitle(props, title);
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
   return (
     <AdminLayout componentTitle={title}>
       <Head>

+ 4 - 0
apps/app/src/pages/admin/customize.page.tsx

@@ -16,6 +16,7 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const CustomizeSettingContents = dynamic(() => import('~/components/Admin/Customize/Customize'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 type Props = CommonProps & {
@@ -40,6 +41,9 @@ const AdminCustomizeSettingsPage: NextPage<Props> = (props) => {
     injectableContainers.push(adminCustomizeContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
 
   return (
     <Provider inject={[...injectableContainers]}>

+ 5 - 0
apps/app/src/pages/admin/data-transfer.page.tsx

@@ -15,6 +15,7 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const G2GDataTransferPage = dynamic(() => import('~/components/Admin/G2GDataTransfer'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 type Props = CommonProps;
@@ -32,6 +33,10 @@ const DataTransferPage: NextPage<Props> = (props) => {
     injectableContainers.push(adminAppContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
   return (
     <Provider inject={[...injectableContainers]}>
       <AdminLayout componentTitle={title}>

+ 5 - 0
apps/app/src/pages/admin/export.page.tsx

@@ -15,6 +15,7 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const ExportArchiveDataPage = dynamic(() => import('~/components/Admin/ExportArchiveDataPage'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 const AdminExportDataArchivePage: NextPage<CommonProps> = (props) => {
@@ -30,6 +31,10 @@ const AdminExportDataArchivePage: NextPage<CommonProps> = (props) => {
     injectableContainers.push(adminAppContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
   return (
     <Provider inject={[...injectableContainers]}>
       <AdminLayout componentTitle={componentTitle}>

+ 4 - 0
apps/app/src/pages/admin/global-notification/[globalNotificationId].page.tsx

@@ -21,6 +21,7 @@ import { retrieveServerSideProps } from '../../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const ManageGlobalNotification = dynamic(() => import('~/components/Admin/Notification/ManageGlobalNotification'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 const AdminGlobalNotificationNewPage: NextPage<CommonProps> = (props) => {
@@ -54,6 +55,9 @@ const AdminGlobalNotificationNewPage: NextPage<CommonProps> = (props) => {
     injectableContainers.push(adminNotificationContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    <ForbiddenPage />;
+  }
 
   return (
     <Provider inject={[...injectableContainers]}>

+ 4 - 0
apps/app/src/pages/admin/global-notification/new.page.tsx

@@ -15,6 +15,7 @@ import { retrieveServerSideProps } from '../../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const ManageGlobalNotification = dynamic(() => import('~/components/Admin/Notification/ManageGlobalNotification'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 const AdminGlobalNotificationNewPage: NextPage<CommonProps> = (props) => {
@@ -29,6 +30,9 @@ const AdminGlobalNotificationNewPage: NextPage<CommonProps> = (props) => {
     injectableContainers.push(adminNotificationContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    <ForbiddenPage />;
+  }
 
   return (
     <Provider inject={[...injectableContainers]}>

+ 5 - 0
apps/app/src/pages/admin/importer.page.tsx

@@ -15,6 +15,7 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const DataImportPageContents = dynamic(() => import('~/components/Admin/ImportData/ImportDataPageContents'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 const AdminDataImportPage: NextPage<CommonProps> = (props) => {
@@ -30,6 +31,10 @@ const AdminDataImportPage: NextPage<CommonProps> = (props) => {
     injectableContainers.push(adminImportContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
 
   return (
     <Provider inject={[...injectableContainers]}>

+ 9 - 1
apps/app/src/pages/admin/index.page.tsx

@@ -10,12 +10,16 @@ import { Container, Provider } from 'unstated';
 import AdminHomeContainer from '~/client/services/AdminHomeContainer';
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { CommonProps, generateCustomTitle } from '~/pages/utils/commons';
-import { useCurrentUser, useGrowiCloudUri, useGrowiAppIdForGrowiCloud } from '~/stores/context';
+import {
+  useCurrentUser, useGrowiCloudUri, useGrowiAppIdForGrowiCloud,
+} from '~/stores/context';
+
 
 import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const AdminHome = dynamic(() => import('~/components/Admin/AdminHome/AdminHome'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 type Props = CommonProps & {
@@ -45,6 +49,10 @@ const AdminHomepage: NextPage<Props> = (props) => {
     injectableContainers.push(adminHomeContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
 
   return (
     <Provider inject={[...injectableContainers]}>

+ 4 - 0
apps/app/src/pages/admin/markdown.page.tsx

@@ -16,6 +16,7 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const MarkDownSettingContents = dynamic(() => import('~/components/Admin/MarkdownSetting/MarkDownSettingContents'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 const AdminMarkdownPage: NextPage<CommonProps> = (props) => {
@@ -32,6 +33,9 @@ const AdminMarkdownPage: NextPage<CommonProps> = (props) => {
     injectableContainers.push(adminMarkDownContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
 
   return (
     <Provider inject={[...injectableContainers]}>

+ 5 - 0
apps/app/src/pages/admin/notification.page.tsx

@@ -15,6 +15,7 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const NotificationSetting = dynamic(() => import('~/components/Admin/Notification/NotificationSetting'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 const AdminExternalNotificationPage: NextPage<CommonProps> = (props) => {
@@ -31,6 +32,10 @@ const AdminExternalNotificationPage: NextPage<CommonProps> = (props) => {
     injectableContainers.push(adminNotificationContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
 
   return (
     <Provider inject={[...injectableContainers]}>

+ 5 - 0
apps/app/src/pages/admin/plugins.page.tsx

@@ -21,6 +21,7 @@ const PluginsExtensionPageContents = dynamic(
   () => import('~/features/growi-plugin/client/components/Admin').then(mod => mod.PluginsExtensionPageContents),
   { ssr: false },
 );
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 const AdminAppPage: NextPage<CommonProps> = (props) => {
@@ -36,6 +37,10 @@ const AdminAppPage: NextPage<CommonProps> = (props) => {
     injectableContainers.push(adminAppContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
   return (
     <Provider inject={[...injectableContainers]}>
       <AdminLayout componentTitle={title} >

+ 5 - 0
apps/app/src/pages/admin/search.page.tsx

@@ -15,6 +15,7 @@ const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { s
 const FullTextSearchManagement = dynamic(
   () => import('~/components/Admin//FullTextSearchManagement').then(mod => mod.FullTextSearchManagement), { ssr: false },
 );
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 type Props = CommonProps & {
@@ -30,6 +31,10 @@ const AdminFullTextSearchManagementPage: NextPage<Props> = (props) => {
   const title = t('full_text_search_management.full_text_search_management');
   const headTitle = generateCustomTitle(props, title);
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
   return (
     <AdminLayout componentTitle={title}>
       <Head>

+ 5 - 0
apps/app/src/pages/admin/security.page.tsx

@@ -22,6 +22,7 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const SecurityManagement = dynamic(() => import('~/components/Admin/Security/SecurityManagement'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 type Props = CommonProps & {
@@ -64,6 +65,10 @@ const AdminSecuritySettingsPage: NextPage<Props> = (props) => {
     }
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
   return (
     <Provider inject={[...adminSecurityContainers]}>
       <AdminLayout componentTitle={componentTitle}>

+ 5 - 1
apps/app/src/pages/admin/slack-integration-legacy.page.tsx

@@ -15,7 +15,7 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const LegacySlackIntegration = dynamic(() => import('~/components/Admin/LegacySlackIntegration/LegacySlackIntegration'), { ssr: false });
-
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 const AdminLegacySlackIntegrationPage: NextPage<CommonProps> = (props) => {
   const { t } = useTranslation('admin');
@@ -30,6 +30,10 @@ const AdminLegacySlackIntegrationPage: NextPage<CommonProps> = (props) => {
     injectableContainers.push(adminSlackIntegrationLegacyContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
 
   return (
     <Provider inject={[...injectableContainers]}>

+ 5 - 0
apps/app/src/pages/admin/slack-integration.page.tsx

@@ -14,6 +14,7 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const SlackIntegration = dynamic(() => import('~/components/Admin/SlackIntegration/SlackIntegration'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 type Props = CommonProps & {
@@ -29,6 +30,10 @@ const AdminSlackIntegrationPage: NextPage<Props> = (props) => {
   const componentTitle = t('slack_integration.slack_integration');
   const pageTitle = generateCustomTitle(props, componentTitle);
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
   return (
     <AdminLayout componentTitle={componentTitle}>
       <Head>

+ 5 - 0
apps/app/src/pages/admin/user-group-detail/[userGroupId].page.tsx

@@ -15,6 +15,7 @@ import { retrieveServerSideProps } from '../../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const UserGroupDetailPage = dynamic(() => import('~/components/Admin/UserGroupDetail/UserGroupDetailPage'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 type Props = CommonProps & {
   isAclEnabled: boolean
@@ -34,6 +35,10 @@ const AdminUserGroupDetailPage: NextPage<Props> = (props: Props) => {
 
   useIsAclEnabled(props.isAclEnabled);
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
   return (
     <AdminLayout componentTitle={title}>
       <Head>

+ 5 - 0
apps/app/src/pages/admin/user-groups.page.tsx

@@ -13,6 +13,7 @@ import { retrieveServerSideProps } from '../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const UserGroupPage = dynamic(() => import('~/components/Admin/UserGroup/UserGroupPage').then(mod => mod.UserGroupPage), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 type Props = CommonProps & {
@@ -28,6 +29,10 @@ const AdminUserGroupPage: NextPage<Props> = (props) => {
   const title = t('user_group_management.user_group_management');
   const headTitle = generateCustomTitle(props, title);
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
+
   return (
     <AdminLayout componentTitle={title}>
       <Head>

+ 4 - 0
apps/app/src/pages/admin/users/external-accounts.page.tsx

@@ -15,6 +15,7 @@ import { retrieveServerSideProps } from '../../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
 const ManageExternalAccount = dynamic(() => import('~/components/Admin/ManageExternalAccount'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 const AdminUserManagementPage: NextPage<CommonProps> = (props) => {
@@ -32,6 +33,9 @@ const AdminUserManagementPage: NextPage<CommonProps> = (props) => {
     );
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
 
   return (
     <Provider inject={[...injectableContainers]}>

+ 4 - 1
apps/app/src/pages/admin/users/index.page.tsx

@@ -15,8 +15,8 @@ import { useCurrentUser, useIsMailerSetup } from '~/stores/context';
 import { retrieveServerSideProps } from '../../../utils/admin-page-util';
 
 const AdminLayout = dynamic(() => import('~/components/Layout/AdminLayout'), { ssr: false });
-
 const UserManagement = dynamic(() => import('~/components/Admin/UserManagement'), { ssr: false });
+const ForbiddenPage = dynamic(() => import('~/components/Admin/ForbiddenPage').then(mod => mod.ForbiddenPage), { ssr: false });
 
 
 type Props = CommonProps & {
@@ -39,6 +39,9 @@ const AdminUserManagementPage: NextPage<Props> = (props) => {
     injectableContainers.push(adminUsersContainer);
   }
 
+  if (props.isAccessDeniedForNonAdminUser) {
+    return <ForbiddenPage />;
+  }
 
   return (
     <Provider inject={[...injectableContainers]}>

+ 1 - 0
apps/app/src/pages/utils/commons.ts

@@ -31,6 +31,7 @@ export type CommonProps = {
   redirectDestination: string | null,
   isDefaultLogo: boolean,
   growiCloudUri: string,
+  isAccessDeniedForNonAdminUser?: boolean,
   currentUser?: IUserHasId,
   forcedColorScheme?: ColorScheme,
   sidebarConfig: ISidebarConfig,

+ 0 - 1
apps/app/src/server/middlewares/admin-required.js

@@ -26,5 +26,4 @@ module.exports = (crowi, fallback = null) => {
     }
     return res.redirect('/login');
   };
-
 };

+ 4 - 0
apps/app/src/utils/admin-page-util.ts

@@ -44,6 +44,10 @@ export const retrieveServerSideProps: any = async(
     props.currentUser = user.toObject();
   }
 
+  props.isAccessDeniedForNonAdminUser = props.currentUser == null
+    ? true
+    : !props.currentUser.admin;
+
   await injectNextI18NextConfigurations(context, props, ['admin', 'commons']);
 
   return {