次の方法で共有


チュートリアル: ネイティブ認証 JavaScript SDK を使用して React シングルページ アプリにユーザーをサインインする

適用対象: 次の内容が外部テナントに適用されることを示す白いチェック マーク記号が付いた緑の円。 外部テナント (詳細)

このチュートリアルでは、ネイティブ認証 JavaScript SDK を使用して React シングルページ アプリ (SPA) にユーザーをサインインさせる方法について説明します。

このチュートリアルでは、次の操作を行います。

  • React アプリを更新してユーザーをサインインさせる。
  • サインイン フローをテストします。

[前提条件]

UI コンポーネントを作成する

このセクションでは、ユーザーのサインイン情報を収集するフォームを作成します。

  1. src/app/sign-in という名前のフォルダーを作成します。

  2. サインイン/コンポーネント/InitialForm.tsx ファイルを作成し、サインイン/コンポーネント/InitialForm.tsx からコードを貼り付けます。 このコンポーネントには、ユーザーのユーザー名 (電子メール) を収集するフォームが表示されます。

  3. 認証方法が電子メールとワンタイム パスコードの場合は、 サインイン/コンポーネント/CodeForm.tsx ファイルを作成し、 サインイン/コンポーネント/CodeForm.tsx からコードを貼り付けます。 管理者が Microsoft Entra 管理センターのサインイン フローとしてメール ワンタイム パスコードを設定した場合、このコンポーネントはユーザーからワンタイム パスコードを収集するフォームを表示します。

  4. 認証方法が電子メールとパスワードの場合は、 サインイン/コンポーネント/PasswordForm.tsx ファイルを作成し、 サインイン/コンポーネント/PasswordForm.tsx からコードを貼り付けます。 このコンポーネントには、ユーザーのパスワードを収集するフォームが表示されます。

  5. サインイン/コンポーネント/UserInfo.tsx ファイルを作成し、サインイン/コンポーネント/UserInfo.tsx からコードを貼り付けます。 このコンポーネントには、サインインしているユーザーのユーザー名とサインイン状態が表示されます。

フォームの操作を処理する

このセクションでは、サインイン フローの開始、ユーザー パスワードの送信、ワンタイム パスコードなど、サインイン フォームの操作を処理するコードを追加します。

サインイン フローのロジックを処理する サインイン/ページ.tsx ファイルを作成します。 このファイルでは、次の操作を行います。

  • 必要なコンポーネントをインポートし、状態に基づいて適切なフォームを表示します。 サインイン/ページ.tsx の完全な例を参照してください。

    import {
      CustomAuthPublicClientApplication,
      ICustomAuthPublicClientApplication,
      SignInCodeRequiredState,
      // Uncommon if using a Email + Password flow
      // SignInPasswordRequiredState,
      SignInCompletedState,
      AuthFlowStateBase,
    } from "@azure/msal-browser/custom-auth";
    
    export default function SignIn() {
        const [authClient, setAuthClient] = useState<ICustomAuthPublicClientApplication | null>(null);
        const [username, setUsername] = useState("");
        //If you are sign in using a Email + Password flow, uncomment the following line
        //const [password, setPassword] = useState("");
        const [code, setCode] = useState("");
        const [error, setError] = useState("");
        const [loading, setLoading] = useState(false);
        const [signInState, setSignInState] = useState<AuthFlowStateBase | null>(null);
        const [data, setData] = useState<CustomAuthAccountData | undefined>(undefined);
        const [loadingAccountStatus, setLoadingAccountStatus] = useState(true);
        const [isSignedIn, setCurrentSignInStatus] = useState(false);
    
        useEffect(() => {
            const initializeApp = async () => {
                const appInstance = await CustomAuthPublicClientApplication.create(customAuthConfig);
                setAuthClient(appInstance);
            };
    
            initializeApp();
        }, []);
    
        useEffect(() => {
            const checkAccount = async () => {
                if (!authClient) return;
    
                const accountResult = authClient.getCurrentAccount();
    
                if (accountResult.isCompleted()) {
                    setCurrentSignInStatus(true);
                }
    
                setData(accountResult.data);
    
                setLoadingAccountStatus(false);
            };
    
            checkAccount();
        }, [authClient]);
    
        const renderForm = () => {
            if (loadingAccountStatus) {
                return;
            }
    
            if (isSignedIn || signInState instanceof SignInCompletedState) {
                return <UserInfo userData={data} />;
            }
            //If you are signing up using Email + Password flow, uncomment the following block of code
            /*
            if (signInState instanceof SignInPasswordRequiredState) {
                return (
                    <PasswordForm
                        onSubmit={handlePasswordSubmit}
                        password={password}
                        setPassword={setPassword}
                        loading={loading}
                    />
                );
            }
            */
            if (signInState instanceof SignInCodeRequiredState) {
                return <CodeForm onSubmit={handleCodeSubmit} code={code} setCode={setCode} loading={loading} />;
            }
    
            return <InitialForm onSubmit={startSignIn} username={username} setUsername={setUsername} loading={loading} />;
        };
    
        return (
            <div style={styles.container}>
                <h2 style={styles.h2}>Sign In</h2>
                <>
                    {renderForm()}
                    {error && <div style={styles.error}>{error}</div>}
                </>
            </div>
        );
    }
    
  • サインイン フローを開始するには、次のコード スニペットを使用します。 コード スニペットを配置する場所については、 サインイン/ページ.tsx の完全な例を参照してください。

    const startSignIn = async (e: React.FormEvent) => {
        e.preventDefault();
        setError("");
        setLoading(true);
    
        if (!authClient) return;
    
        // Start the sign-in flow
        const result = await authClient.signIn({
            username,
        });
    
        // Thge result may have the different states,
        // such as Password required state, OTP code rquired state, Failed state and Completed state.
    
        if (result.isFailed()) {
            if (result.error?.isUserNotFound()) {
                setError("User not found");
            } else if (result.error?.isInvalidUsername()) {
                setError("Username is invalid");
            } else if (result.error?.isPasswordIncorrect()) {
                setError("Password is invalid");
    
            } else {
                setError(`An error occurred: ${result.error?.errorData?.errorDescription}`);
            }
        }
    
        if (result.isCompleted()) {
            setData(result.data);
        }
    
        setSignInState(result.state);
    
        setLoading(false);
    };
    

    SDK のインスタンス メソッド signIn()、サインイン フローが開始されます。

  • 選択した認証フローが電子メールとワンタイム パスコードの場合は、次のコード スニペットを使用してワンタイム パスコードを送信します。 コード スニペットを配置する場所については、 サインイン/ページ.tsx の完全な例を参照してください。

    const handleCodeSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        setError("");
        setLoading(true);
    
        if (signInState instanceof SignInCodeRequiredState) {
            const result = await signInState.submitCode(code);
    
            // the result object may have the different states, such as Failed state and Completed state.
    
            if (result.isFailed()) {
                if (result.error?.isInvalidCode()) {
                    setError("Invalid code");
                } else {
                    setError(result.error?.errorData?.errorDescription || "An error occurred while verifying the code");
                }
            }
    
            if (result.isCompleted()) {
                setData(result.data);
                setSignInState(result.state);
            }
        }
    
        setLoading(false);
    };
    

    サインイン状態の submitCode() はワンタイム パスコードを送信します。

  • 選択した認証フローが電子メールとパスワードの場合は、次のコード スニペットを使用してユーザーのパスワードを送信します。 コード スニペットを配置する場所については、 サインイン/ページ.tsx の完全な例を参照してください。

    const handlePasswordSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        setError("");
        setLoading(true);
    
        if (signInState instanceof SignInPasswordRequiredState) {
            const result = await signInState.submitPassword(password);
    
            if (result.isFailed()) {
                if (result.error?.isInvalidPassword()) {
                    setError("Incorrect password");
                } else {
                    setError(
                        result.error?.errorData?.errorDescription || "An error occurred while verifying the password"
                    );
                }
            }
    
            if (result.isCompleted()) {
                setData(result.data);
    
                setSignInState(result.state);
            }
        }
    
        setLoading(false);
    };
    

    サインイン状態の submitPassword() は、ユーザーのパスワードを送信します。

サインアップ エラーを処理する

サインイン中、すべてのアクションが成功するわけではありません。 たとえば、ユーザーが存在しないユーザー名でサインインしようとしたり、無効な電子メール ワンタイム パスコードや、最小要件を満たしていないパスワードを送信しようとしたりすることがあります。 次の場合は、エラーを適切に処理してください。

  • signIn() メソッドでサインイン フローを開始します。

  • submitCode() メソッドでワンタイム パスコードを送信します。

  • submitPassword()メソッドでパスワードを送信します。 このエラーは、選択したサインアップ フローが電子メールとパスワードで行われる場合に処理します。

signIn() メソッドの結果として発生する可能性があるエラーの 1 つがresult.error?.isRedirectRequired()。 このシナリオは、認証フローを完了するのにネイティブ認証だけでは十分ではない場合に発生します。 たとえば、承認サーバーにクライアントが提供できない機能が必要な場合です。 ネイティブ認証 Web フォールバックの詳細と、React アプリで Web フォールバックをサポートする方法について説明します。

アプリを実行してテストする

アプリの実行とテスト 」の手順に従ってアプリを実行し、サインイン フローをテストします。

エイリアスまたはユーザー名を使用してサインインを有効にする

メール アドレスとパスワードを使用してサインインするユーザーも、ユーザー名とパスワードでサインインできます。 代替サインイン識別子とも呼ばれるユーザー名には、顧客 ID、アカウント番号、またはユーザー名として使用する別の識別子を指定できます。

Microsoft Entra 管理センターを使用してユーザー アカウントにユーザー名を手動で割り当てたり、Microsoft Graph API を使用してアプリで自動化したりできます。

「エイリアスまたはユーザー名を使用してサインインする」の記事の手順を使用して、ユーザーがアプリケーションでユーザー名を使用してサインインできるようにします。

  1. サインインでユーザー名を有効にします
  2. 管理センターでユーザー名を持つユーザーを作成するか、ユーザー名追加して既存のユーザーを更新します。 または、 Microsoft Graph API を使用して、アプリでのユーザーの作成と更新を自動化することもできます。