Sdílet prostřednictvím


Kurz: Registrace uživatelů do jednostránka aplikace React pomocí nativní sady JavaScript SDK pro ověřování (Preview)

Platí pro: Zelený kruh se symbolem bílé značky zaškrtnutí, který označuje následující obsah platí pro externí tenanty. Externí tenanti (další informace)

V tomto kurzu se dozvíte, jak vytvořit jednostráňovou aplikaci React, která zaregistruje uživatele pomocí sady JavaScript SDK nativního ověřování.

V tomto kurzu se naučíte:

  • Vytvořte projekt React Next.js.
  • Přidejte do ní sadu MSAL JS SDK.
  • Přidejte součásti uživatelského rozhraní aplikace.
  • Nastavte projekt pro registraci uživatelů.

Požadavky

Vytvoření projektu React a instalace závislostí

V umístění podle výběru v počítači spusťte následující příkazy a vytvořte nový projekt React s názvem reactspa, přejděte do složky projektu a pak nainstalujte balíčky:

npx create-next-app@latest
cd reactspa
npm install

Po úspěšném spuštění příkazů byste měli mít aplikaci s následující strukturou:

spasample/
└──node_modules/
   └──...
└──public/
   └──...
└──src/
   └──app/
      └──favicon.ico
      └──globals.css
      └──page.tsx
      └──layout.tsx
└──postcss.config.mjs
└──package-lock.json
└──package.json
└──tsconfig.json
└──README.md
└──next-env.d.ts
└──next.config.ts

Přidání sady JavaScript SDK do projektu

Pokud chcete v aplikaci použít nativní sadu JavaScript SDK pro ověřování, pomocí terminálu ji nainstalujte pomocí následujícího příkazu:

npm install @azure/msal-browser

Nativní možnosti ověřování jsou součástí azure-msal-browser knihovny. Chcete-li použít nativní funkce ověřování, importujete z @azure/msal-browser/custom-auth. Například:

  import CustomAuthPublicClientApplication from "@azure/msal-browser/custom-auth";

Přidání konfigurace klienta

V této části definujete konfiguraci nativní ověřovací veřejné klientské aplikace, která umožňuje interakci s rozhraním sady SDK. Uděláte to tak, že vytvoříte soubor src/config/auth-config.ts a pak přidáte následující kód:

export const customAuthConfig: CustomAuthConfiguration = {
  customAuth: {
    challengeTypes: ["password", "oob", "redirect"],
    authApiProxyUrl: "http://localhost:3001/api",
  },
  auth: {
    clientId: "Enter_the_Application_Id_Here",
    authority: "https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com",
    redirectUri: "/",
    postLogoutRedirectUri: "/",
    navigateToLoginRequestUrl: false,
  },
  cache: {
    cacheLocation: "sessionStorage",
  },
  system: {
    loggerOptions: {
      loggerCallback: (
        level: LogLevel,
        message: string,
        containsPii: boolean
      ) => {
        if (containsPii) {
          return;
        }
        switch (level) {
          case LogLevel.Error:
            console.error(message);
            return;
          case LogLevel.Info:
            console.info(message);
            return;
          case LogLevel.Verbose:
            console.debug(message);
            return;
          case LogLevel.Warning:
            console.warn(message);
            return;
        }
      },
    },
  },
};

V kódu vyhledejte zástupný symbol:

  • Enter_the_Application_Id_Here pak ji nahraďte ID aplikace (klienta) aplikace, kterou jste zaregistrovali dříve.

  • Enter_the_Tenant_Subdomain_Here pak ho nahraďte subdoménou tenanta v Centru pro správu Microsoft Entra. Pokud je například primární doména vašeho tenanta contoso.onmicrosoft.com, použijte contoso. Pokud neznáte název svého tenanta, zjistěte, jak získat podrobnosti o tenantovi.

Vytvoření komponent uživatelského rozhraní

Tato aplikace shromažďuje podrobnosti o uživateli, jako je jméno, uživatelské jméno (e-mail), heslo a jednorázové heslo od uživatele. Aplikace tedy musí mít formulář, který tyto informace shromažďuje.

  1. Ve složce src vytvořte složku s názvem src,app/sign-up.

  2. Vytvořte soubor sign-up/components/InitialForm.tsx a vložte kód z registrace/components/InitialForm.tsx. Tato komponenta zobrazí formulář, který shromažďuje atributy registrace uživatele.

  3. Vytvořte soubor sign-up/components/CodeForm.tsx a vložte kód z registrace/components/CodeForm.tsx. Tato komponenta zobrazí formulář, který shromažďuje jednorázové heslo odeslané uživateli. Tento formulář vyžadujete pro e-mail s heslem nebo e-mailem s metodou ověřování jednorázovým heslem.

  4. Pokud je vaše volba metody ověřování e-mailem s heslem, vytvořte soubor sign-up/components/PasswordForm.tsx a vložte kód z registrace/components/PasswordForm.tsx. Tato komponenta zobrazí formulář pro zadání hesla.

Zpracování interakce formuláře

V této části přidáte kód, který zpracovává interakce s formulářem registrace, jako je odeslání podrobností o registraci uživatele nebo jednorázové heslo nebo heslo.

Vytvořte registraci/page.tsx pro zpracování logiky pro tok registrace. V tomto souboru:

  • Naimportujte potřebné součásti a zobrazte správný formulář na základě stavu. Podívejte se na úplný příklad registrace /page.tsx:

        import { useEffect, useState } from "react";
        import { customAuthConfig } from "../../config/auth-config";
        import { styles } from "./styles/styles";
        import { InitialFormWithPassword } from "./components/InitialFormWithPassword";
    
        import {
        CustomAuthPublicClientApplication,
        ICustomAuthPublicClientApplication,
        SignUpCodeRequiredState,
        // Uncomment if your choice of authentication method is email with password
        // SignUpPasswordRequiredState,
        SignUpCompletedState,
        AuthFlowStateBase,
      } from "@azure/msal-browser/custom-auth";
    
        import { SignUpResultPage } from "./components/SignUpResult";
        import { CodeForm } from "./components/CodeForm";
        import { PasswordForm } from "./components/PasswordForm";    
    export default function SignUpPassword() {
        const [authClient, setAuthClient] = useState<ICustomAuthPublicClientApplication | null>(null);
        const [firstName, setFirstName] = useState("");
        const [lastName, setLastName] = useState("");
        const [jobTitle, setJobTitle] = useState("");
        const [city, setCity] = useState("");
        const [country, setCountry] = useState("");
        const [email, setEmail] = useState("");
        //Uncomment if your choice of authentication method is email with password
        //const [password, setPassword] = useState("");
        const [code, setCode] = useState("");
        const [error, setError] = useState("");
        const [loading, setLoading] = useState(false);
        const [signUpState, setSignUpState] = useState<AuthFlowStateBase | null>(null);
        const [loadingAccountStatus, setLoadingAccountStatus] = useState(true);
        const [isSignedIn, setSignInState] = 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()) {
                    setSignInState(true);
                }
                setLoadingAccountStatus(false);
            };
            checkAccount();
        }, [authClient]);
    
        const renderForm = () => {
            if (loadingAccountStatus) {
                return;
            }
            if (isSignedIn) {
                return (
                    <div style={styles.signed_in_msg}>Please sign out before processing the sign up.</div>
                );
            }
            if (signUpState instanceof SignUpCodeRequiredState) {
                return (
                    <CodeForm
                        onSubmit={handleCodeSubmit}
                        code={code}
                        setCode={setCode}
                        loading={loading}
                    />
                );
            } 
            //Uncomment the following block of code if your choice of authentication method is email with password 
            /*
            else if(signUpState instanceof SignUpPasswordRequiredState) {
                return <PasswordForm
                    onSubmit={handlePasswordSubmit}
                    password={password}
                    setPassword={setPassword}
                    loading={loading}
                />;
            }
            */
            else if (signUpState instanceof SignUpCompletedState) {
                return <SignUpResultPage />;
            } else {
                return (
                    <InitialForm
                        onSubmit={handleInitialSubmit}
                        firstName={firstName}
                        setFirstName={setFirstName}
                        lastName={lastName}
                        setLastName={setLastName}
                        jobTitle={jobTitle}
                        setJobTitle={setJobTitle}
                        city={city}
                        setCity={setCity}
                        country={country}
                        setCountry={setCountry}
                        email={email}
                        setEmail={setEmail}
                        loading={loading}
                    />
                );
            }
        }
        return (
            <div style={styles.container}>
                <h2 style={styles.h2}>Sign Up</h2>
                {renderForm()}
                {error && <div style={styles.error}>{error}</div>}
            </div>
        );
    }
    

    Tento kód také vytvoří instanci nativní veřejné klientské aplikace pro ověřování pomocí konfigurace klienta:

    const appInstance = await CustomAuthPublicClientApplication.create(customAuthConfig);
    setAuthClient(appInstance);
    
  • Pokud chcete zpracovat počáteční odeslání formuláře, použijte následující fragment kódu. Podívejte se na úplný příklad na webu sign-up/page.tsx a zjistěte, kam umístit fragment kódu:

    const handleInitialSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        setError("");
        setLoading(true);
    
        if (!authClient) return;
    
        const attributes: UserAccountAttributes = {
            displayName: `${firstName} ${lastName}`,
            givenName: firstName,
            surname: lastName,
            jobTitle: jobTitle,
            city: city,
            country: country,
        };
    
        const result = await authClient.signUp({
            username: email,
            attributes
        });
        const state = result.state;
    
        if (result.isFailed()) {
            if (result.error?.isUserAlreadyExists()) {
                setError("An account with this email already exists");
            } else if (result.error?.isInvalidUsername()) {
                setError("Invalid uername");
            } else if (result.error?.isInvalidPassword()) {
                setError("Invalid password");
            } else if (result.error?.isAttributesValidationFailed()) {
                setError("Invalid attributes");
            } else if (result.error?.isMissingRequiredAttributes()) {
                setError("Missing required attributes");
            } else {
                setError(result.error?.errorData.errorDescription || "An error occurred while signing up");
            }
        } else {
            setSignUpState(state);
        }
        setLoading(false);
    };
    

    Metoda signUp() instance sady SDK spustí tok registrace.

  • K zpracování jednorázového odeslání hesla použijte následující fragment kódu. Podívejte se na úplný příklad na webu sign-up/page.tsx a zjistěte, kam umístit fragment kódu:

    const handleCodeSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        setError("");
        setLoading(true);
    
        try {
            if (signUpState instanceof SignUpCodeRequiredState) {
                const result = await signUpState.submitCode(code);
                if (result.error) {
                    if (result.error.isInvalidCode()) {
                        setError("Invalid verification code");
                    } else {
                        setError("An error occurred while verifying the code");
                    }
                    return;
                }
                if (result.state instanceof SignUpCompletedState) {
                    setSignUpState(result.state);
                }
            }
        } catch (err) {
            setError("An unexpected error occurred");
            console.error(err);
        } finally {
            setLoading(false);
        }
    };
    
  • Pokud chcete zpracovat odeslání hesla, použijte následující fragment kódu. Odeslání hesla zpracováváte, pokud je vaše volba metody ověřování e-mailem s heslem. Podívejte se na úplný příklad na webu sign-up/page.tsx a zjistěte, kam umístit fragment kódu:

        const handlePasswordSubmit = async (e: React.FormEvent) => {
            e.preventDefault();
            setError("");
            setLoading(true);
    
            if (signUpState instanceof SignUpPasswordRequiredState) {
                const result = await signUpState.submitPassword(password);
                const state = result.state;
    
                if (result.isFailed()) {
                    if (result.error?.isInvalidPassword()) {
                        setError("Invalid password");
                    } else {
                        setError(result.error?.errorData.errorDescription || "An error occurred while submitting the password");
                    }
                } else {
                    setSignUpState(state);
                }
            }
    
            setLoading(false);
        };
    
  • Použijte k signUpState instanceof SignUpCompletedState označení, že se uživatel zaregistroval a tok je dokončený. Podívejte se na úplný příklad na adrese sign-up/page.tsx:

    if (signUpState instanceof SignUpCompletedState) {
        return <SignUpResultPage/>;
    }
    

Zpracování chyb registrace

Během registrace nejsou všechny akce úspěšné. Uživatel se například může pokusit zaregistrovat pomocí již použité e-mailové adresy nebo odeslat neplatný e-mail jednorázovým heslem. Ujistěte se, že chyby zpracováváte správně, když:

  • Spusťte tok registrace v signUp() metodě.

  • Odešle jednorázový přístupový kód v submitCode() metodě.

  • Odešlete heslo v submitPassword() metodě. Tuto chybu zpracujete v případě, že váš výběr toku registrace je e-mailem a heslem.

Jednou z chyb, které mohou být výsledkem metody signUp() , je result.error?.isRedirectRequired(). K tomuto scénáři dochází v případě, že k dokončení toku ověřování nestačí nativní ověřování. Pokud například autorizační server vyžaduje možnosti, které klient nemůže poskytnout. Přečtěte si další informace o náhradním webu nativního ověřování a o tom, jak podporovat záložní web v aplikaci React.

Volitelné: Automatické přihlášení uživatelů po registraci

Jakmile se uživatel úspěšně zaregistruje, můžete ho přímo přihlásit do aplikace, aniž byste zahájili nový tok přihlašování. K tomu použijte následující fragment kódu. Podívejte se na úplný příklad na adrese sign-up/page.tsx:

if (signUpState instanceof SignUpCompletedState) {
    const result = await signUpState.signIn();
    const state = result.state;
    if (result.isFailed()) {
        setError(result.error?.errorData?.errorDescription || "An error occurred during auto sign-in");
    }
    
    if (result.isCompleted()) {
        setData(result.data);
        setSignUpState(state);
    }
}

Spuštění a otestování aplikace

  1. Otevřete okno terminálu a přejděte do kořenové složky aplikace:

    cd reactspa
    
  2. Pokud chcete spustit proxy server CORS, spusťte v terminálu následující příkaz:

    npm run cors
    
  3. Pokud chcete spustit aplikaci React, otevřete další okno terminálu a spusťte následující příkaz:

    cd reactspa
    npm start
    
  4. Otevřete webový prohlížeč a přejděte na http://localhost:3000/sign-up. Zobrazí se registrační formulář.

  5. Pokud se chcete zaregistrovat k účtu, zadejte podrobnosti, vyberte tlačítko Pokračovat a postupujte podle pokynů.

Dále můžete aplikaci React aktualizovat tak, aby se přihlásila uživatele nebo resetovala heslo uživatele.

Nastavení poweredByHeader na false v next.config.js

Ve výchozím nastavení je hlavička x-powered-by obsažena v odpovědích HTTP, která indikuje, že aplikace je poháněna Next.js. Z důvodů zabezpečení nebo přizpůsobení ale můžete chtít odebrat nebo upravit tuto hlavičku:

const nextConfig: NextConfig = {
  poweredByHeader: false,
  /* other config options here */
};

Další krok