共用方式為


教學課程:使用原生驗證 JavaScript SDK 登入 React 單頁應用程式

適用於帶有白色核取記號符號的綠色圓圈,表示下列內容適用於外部租用戶。 外部租用戶 (深入瞭解

在本教學課程中,您將瞭解如何使用原生驗證 JavaScript SDK 將使用者登入 React 單頁應用程式 (SPA)。

在本教學課程中,您會:

  • 更新 React 應用程式以登入使用者。
  • 測試登入流程。

先決條件

建立UI元件

在這個章節,您會建立表單,用以收集使用者的登入資訊:

  1. 建立名為 src/app/sign-in 的資料夾。

  2. 建立 登入/components/InitialForm.tsx 檔案,然後從 sign-in/components/InitialForm.tsx 貼上程序代碼。 此元件會顯示一個表單,用於收集使用者的使用者名稱(電子郵件)。

  3. 如果您選擇的驗證方法是電子郵件和一次性密碼,請建立 登入/components/CodeForm.tsx 檔案,然後貼上 登入/components/CodeForm.tsx 的程序代碼。 如果系統管理員在 Microsoft Entra 系統管理中心將電子郵件一次性密碼設定為登入流程,則此元件會顯示表單體,以從使用者收集單次密碼。

  4. 如果您選擇的驗證方法是電子郵件和密碼,請建立 登入/components/PasswordForm.tsx 檔案,然後從 登入/components/PasswordForm.tsx 貼上程序代碼。 此元件會顯示收集使用者密碼的表單。

  5. 建立 登入/元件/UserInfo.tsx 檔案,然後貼上 登入/元件/UserInfo.tsx 的程序代碼。 此元件會顯示登入的用戶名稱和登入狀態。

處理表單互動

在本節中,您會新增程式碼來處理登入窗體互動,例如啟動登入流程、提交用戶密碼或一次性密碼。

建立 登入/page.tsx 檔案來處理登入流程的邏輯。 在這個檔案中:

  • 匯入必要的元件,並根據狀態顯示適當的表單。 請參閱 登入/page.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>
        );
    }
    
  • 若要啟動登入流程,請使用下列代碼段。 請參閱 登入/page.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()會啟動登入流程。

  • 如果您選擇的驗證流程是電子郵件和單次密碼,請使用下列代碼段提交一次性密碼。 請參閱 登入/page.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() 會提交一次性密碼。

  • 如果您選擇的驗證流程是電子郵件和密碼,請使用下列代碼段提交用戶的密碼。 請參閱 登入/page.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() 方法可能產生的錯誤之一是 result.error?.isRedirectRequired()。 當原生驗證不足以完成驗證流程時,就會發生此案例。 例如,如果授權伺服器需要客戶端無法提供的功能。 深入瞭解 原生驗證 Web 後援 ,以及如何在 React 應用程式中 支援 Web 後援

執行及測試您的應用程式

使用 執行和測試應用程式 中的步驟來執行您的應用程式,然後測試登入流程。

啟用別名或使用者名稱登入

您可以允許使用電子郵件地址和密碼登入的使用者也使用使用者名稱和密碼登入。 使用者名稱也稱為替代登入識別碼,可以是客戶 ID、帳號,或你選擇使用的其他識別碼作為使用者名稱。

你可以透過 Microsoft Entra 管理中心手動將使用者名稱指派給使用者帳號,或透過 Microsoft Graph API 在應用程式中自動化此流程。

請使用「 以別名或使用者名稱登入 」文章中的步驟,讓你的使用者能在應用程式中使用使用者名登入:

  1. 登入時啟用使用者名稱
  2. 管理中心建立使用者名稱,或透過新增使用者名稱更新現有使用者。 另外,你也可以 使用 Microsoft Graph API 自動化應用程式中的使用者建立與更新