Просмотр исходного кода

Merge pull request #8648 from weseek/fix/login-with-external-auth-provider

fix: Login buttons for external auth provider does not work
Yuki Takei 2 лет назад
Родитель
Сommit
2ae2cabdbb

+ 2 - 1
apps/app/src/components/CompleteUserRegistration.tsx

@@ -1,4 +1,5 @@
-import React, { FC } from 'react';
+import type { FC } from 'react';
+import React from 'react';
 
 import { useTranslation } from 'next-i18next';
 

+ 44 - 0
apps/app/src/components/LoginForm/ExternalAuthButton.tsx

@@ -0,0 +1,44 @@
+import { useCallback } from 'react';
+
+import { IExternalAuthProviderType } from '@growi/core';
+import { useTranslation } from 'next-i18next';
+
+const authIcon = {
+  [IExternalAuthProviderType.google]: <span className="growi-custom-icons align-bottom">google</span>,
+  [IExternalAuthProviderType.github]: <span className="growi-custom-icons align-bottom">github</span>,
+  [IExternalAuthProviderType.facebook]: <span className="growi-custom-icons align-bottom">facebook</span>,
+  [IExternalAuthProviderType.oidc]: <span className="growi-custom-icons align-bottom">openid</span>,
+  [IExternalAuthProviderType.saml]: <span className="material-symbols-outlined align-bottom">key</span>,
+};
+
+const authLabel = {
+  [IExternalAuthProviderType.google]: 'Google',
+  [IExternalAuthProviderType.github]: 'GitHub',
+  [IExternalAuthProviderType.facebook]: 'Facebook',
+  [IExternalAuthProviderType.oidc]: 'OIDC',
+  [IExternalAuthProviderType.saml]: 'SAML',
+};
+
+
+export const ExternalAuthButton = ({ authType }: {authType: IExternalAuthProviderType}): JSX.Element => {
+  const { t } = useTranslation();
+
+  const key = `btn-auth-${authType.toString()}`;
+  const btnClass = `btn-auth-${authType.toString()}`;
+
+  const handleLoginWithExternalAuth = useCallback(() => {
+    window.location.href = `/passport/${authType.toString()}`;
+  }, [authType]);
+
+  return (
+    <button
+      key={key}
+      type="button"
+      className={`btn btn-secondary ${btnClass} my-2 col-10 col-sm-7 mx-auto d-flex`}
+      onClick={handleLoginWithExternalAuth}
+    >
+      <span>{authIcon[authType]}</span>
+      <span className="flex-grow-1">{t('Sign in with External auth', { signin: authLabel[authType] })}</span>
+    </button>
+  );
+};

+ 0 - 0
apps/app/src/components/LoginForm.module.scss → apps/app/src/components/LoginForm/LoginForm.module.scss


+ 15 - 48
apps/app/src/components/LoginForm.tsx → apps/app/src/components/LoginForm/LoginForm.tsx

@@ -2,6 +2,7 @@ import React, {
   useState, useEffect, useCallback,
 } from 'react';
 
+import type { IExternalAuthProviderType } from '@growi/core';
 import { LoadingSpinner } from '@growi/ui/dist/components';
 import { useTranslation } from 'next-i18next';
 import { useRouter } from 'next/router';
@@ -14,12 +15,15 @@ import type { IErrorV3 } from '~/interfaces/errors/v3-error';
 import { RegistrationMode } from '~/interfaces/registration-mode';
 import { toArrayIfNot } from '~/utils/array-utils';
 
-import { CompleteUserRegistration } from './CompleteUserRegistration';
+import { CompleteUserRegistration } from '../CompleteUserRegistration';
+
+import { ExternalAuthButton } from './ExternalAuthButton';
 
 import styles from './LoginForm.module.scss';
 
 const moduleClass = styles['login-form'];
 
+
 type LoginFormProps = {
   username?: string,
   name?: string,
@@ -31,7 +35,7 @@ type LoginFormProps = {
   isLocalStrategySetup: boolean,
   isLdapStrategySetup: boolean,
   isLdapSetupFailed: boolean,
-  objOfIsExternalAuthEnableds?: any,
+  enabledExternalAuthType?: IExternalAuthProviderType[],
   isMailerSetup?: boolean,
   externalAccountLoginError?: IExternalAccountLoginError,
 }
@@ -42,10 +46,10 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
 
   const {
     isLocalStrategySetup, isLdapStrategySetup, isLdapSetupFailed, isPasswordResetEnabled,
-    isEmailAuthenticationEnabled, registrationMode, registrationWhitelist, isMailerSetup, objOfIsExternalAuthEnableds,
+    isEmailAuthenticationEnabled, registrationMode, registrationWhitelist, isMailerSetup, enabledExternalAuthType,
   } = props;
   const isLocalOrLdapStrategiesEnabled = isLocalStrategySetup || isLdapStrategySetup;
-  const isSomeExternalAuthEnabled = Object.values(objOfIsExternalAuthEnableds).some(elem => elem);
+  const isSomeExternalAuthEnabled = enabledExternalAuthType != null && enabledExternalAuthType.length > 0;
 
   // states
   const [isRegistering, setIsRegistering] = useState(false);
@@ -81,12 +85,6 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
     return t(key);
   }, [t]);
 
-  const handleLoginWithExternalAuth = useCallback((e) => {
-    const auth = e.currentTarget.id;
-
-    window.location.href = `/passport/${auth}`;
-  }, []);
-
   const resetLoginErrors = useCallback(() => {
     if (loginErrors.length === 0) return;
     setLoginErrors([]);
@@ -265,38 +263,12 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
   ]);
 
 
-  const renderExternalAuthInput = useCallback((auth) => {
-    const authIcon = {
-      google: <span className="growi-custom-icons align-bottom">google</span>,
-      github: <span className="growi-custom-icons align-bottom">github</span>,
-      facebook: <span className="growi-custom-icons align-bottom">facebook</span>,
-      oidc: <span className="growi-custom-icons align-bottom">openid</span>,
-      saml: <span className="material-symbols-outlined align-bottom">key</span>,
-    };
-    const authBtn = `btn-auth-${auth}`;
-    const signin = {
-      google: 'Google',
-      github: 'GitHub',
-      facebook: 'Facebook',
-      oidc: 'OIDC',
-      saml: 'SAML',
-    };
-
-    return (
-      <button
-        key={`btn-auth-${auth}`}
-        type="button"
-        className={`btn btn-secondary ${authBtn} my-2 col-10 col-sm-7 mx-auto d-flex`}
-        onClick={handleLoginWithExternalAuth}
-      >
-        <span>{authIcon[auth]}</span>
-        <span className="flex-grow-1">{t('Sign in with External auth', { signin: signin[auth] })}</span>
-      </button>
-    );
-  }, [handleLoginWithExternalAuth, t]);
-
   const renderExternalAuthLoginForm = useCallback(() => {
-    const { objOfIsExternalAuthEnableds } = props;
+    const { enabledExternalAuthType } = props;
+
+    if (enabledExternalAuthType == null) {
+      return <></>;
+    }
 
     return (
       <>
@@ -304,16 +276,11 @@ export const LoginForm = (props: LoginFormProps): JSX.Element => {
           <p className="text-white mb-0">{t('or')}</p>
         </div>
         <div className="mt-2">
-          {Object.keys(objOfIsExternalAuthEnableds).map((auth) => {
-            if (!objOfIsExternalAuthEnableds[auth]) {
-              return;
-            }
-            return renderExternalAuthInput(auth);
-          })}
+          { enabledExternalAuthType.map(authType => <ExternalAuthButton authType={authType} />) }
         </div>
       </>
     );
-  }, [props, t, renderExternalAuthInput]);
+  }, [props, t]);
 
   const resetRegisterErrors = useCallback(() => {
     if (registerErrors.length === 0) return;

+ 1 - 0
apps/app/src/components/LoginForm/index.ts

@@ -0,0 +1 @@
+export * from './LoginForm';

+ 16 - 15
apps/app/src/pages/login/index.page.tsx

@@ -1,6 +1,7 @@
 import React from 'react';
 
-import {
+import { IExternalAuthProviderType } from '@growi/core';
+import type {
   NextPage, GetServerSideProps, GetServerSidePropsContext,
 } from 'next';
 import { useTranslation } from 'next-i18next';
@@ -10,11 +11,11 @@ import Head from 'next/head';
 import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
 import { LoginForm } from '~/components/LoginForm';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
-import { IExternalAccountLoginError, isExternalAccountLoginError } from '~/interfaces/errors/external-account-login-error';
+import type { IExternalAccountLoginError } from '~/interfaces/errors/external-account-login-error';
+import { isExternalAccountLoginError } from '~/interfaces/errors/external-account-login-error';
 import type { RegistrationMode } from '~/interfaces/registration-mode';
-import {
-  CommonProps, getServerSideCommonProps, generateCustomTitle, getNextI18NextConfig,
-} from '~/pages/utils/commons';
+import type { CommonProps } from '~/pages/utils/commons';
+import { getServerSideCommonProps, generateCustomTitle, getNextI18NextConfig } from '~/pages/utils/commons';
 import {
   useCsrfToken,
   useCurrentPathname,
@@ -27,7 +28,7 @@ type Props = CommonProps & {
   registrationMode: RegistrationMode,
   pageWithMetaStr: string,
   isMailerSetup: boolean,
-  enabledStrategies: unknown,
+  enabledExternalAuthType: IExternalAuthProviderType[],
   registrationWhitelist: string[],
   isLocalStrategySetup: boolean,
   isLdapStrategySetup: boolean,
@@ -55,7 +56,7 @@ const LoginPage: NextPage<Props> = (props: Props) => {
         <title>{title}</title>
       </Head>
       <LoginForm
-        objOfIsExternalAuthEnableds={props.enabledStrategies}
+        enabledExternalAuthType={props.enabledExternalAuthType}
         isLocalStrategySetup={props.isLocalStrategySetup}
         isLdapStrategySetup={props.isLdapStrategySetup}
         isLdapSetupFailed={props.isLdapSetupFailed}
@@ -88,15 +89,15 @@ function injectEnabledStrategies(context: GetServerSidePropsContext, props: Prop
     configManager,
   } = crowi;
 
-  const enabledStrategies = {
-    google: configManager.getConfig('crowi', 'security:passport-google:isEnabled'),
-    github: configManager.getConfig('crowi', 'security:passport-github:isEnabled'),
-    facebook: false,
-    saml: configManager.getConfig('crowi', 'security:passport-saml:isEnabled'),
-    oidc: configManager.getConfig('crowi', 'security:passport-oidc:isEnabled'),
-  };
+  props.enabledExternalAuthType = [
+    configManager.getConfig('crowi', 'security:passport-google:isEnabled') === true ? IExternalAuthProviderType.google : undefined,
+    configManager.getConfig('crowi', 'security:passport-github:isEnabled') === true ? IExternalAuthProviderType.github : undefined,
+    // configManager.getConfig('crowi', 'security:passport-facebook:isEnabled') ?? IExternalAuthProviderType.facebook : undefined,
+    configManager.getConfig('crowi', 'security:passport-saml:isEnabled') === true ? IExternalAuthProviderType.saml : undefined,
+    configManager.getConfig('crowi', 'security:passport-oidc:isEnabled') === true ? IExternalAuthProviderType.oidc : undefined,
 
-  props.enabledStrategies = enabledStrategies;
+  ]
+    .filter((authType): authType is Exclude<typeof authType, undefined> => authType != null);
 }
 
 async function injectServerConfigurations(context: GetServerSidePropsContext, props: Props): Promise<void> {

+ 2 - 1
packages/core/src/interfaces/external-account.ts

@@ -5,9 +5,10 @@ import type { IUser } from './user';
 export const IExternalAuthProviderType = {
   ldap: 'ldap',
   saml: 'saml',
-  oicd: 'oidc',
+  oidc: 'oidc',
   google: 'google',
   github: 'github',
+  facebook: 'facebook',
 } as const;
 
 export type IExternalAuthProviderType = typeof IExternalAuthProviderType[keyof typeof IExternalAuthProviderType]