Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Si applica a:
Tenant esterni (altre informazioni)
Questa esercitazione descrive come creare un'app a pagina singola React che consente agli utenti di iscriversi usando JavaScript SDK per l'autenticazione nativa.
In questa esercitazione, farai:
- Creare un progetto react Next.js.
- Aggiungi MSAL JS SDK a esso.
- Aggiungere componenti dell'interfaccia utente dell'app.
- Configura il progetto per registrare gli utenti.
Prerequisiti
- Completare i passaggi descritti in Avvio rapido: Accedere agli utenti in un'app a pagina singola React usando JavaScript SDK per l'autenticazione nativa. Questa guida introduttiva mostra come eseguire un esempio di codice React.
- Completare i passaggi descritti in Configurare il server proxy CORS per gestire le intestazioni CORS per l'autenticazione nativa.
- Visual Studio Code o un altro editor di codice.
- Node.js.
- Se si vuole consentire agli utenti di iscriversi con un nome utente (alias), abilitare l'attributo utente predefinito Username nel flusso utente di iscrizione. Per la procedura, vedere Abilitare il nome utente nei criteri di identificatore di accesso.
Creare un progetto React e installare le dipendenze
In un percorso preferito nel computer eseguire i comandi seguenti per creare un nuovo progetto React con il nome reactspa, passare alla cartella del progetto e quindi installare i pacchetti:
npx create-next-app@latest
cd reactspa
npm install
Dopo aver eseguito correttamente i comandi, è necessario avere un'app con la struttura seguente:
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
Aggiungere JavaScript SDK al progetto
Per usare JavaScript SDK per l'autenticazione nativa nell'app, usare il terminale per installarlo usando il comando seguente:
npm install @azure/msal-browser
Le funzionalità di autenticazione nativa fanno parte della azure-msal-browser libreria. Per usare le funzionalità di autenticazione nativa, eseguire l'importazione da @azure/msal-browser/custom-auth. Per esempio:
import CustomAuthPublicClientApplication from "@azure/msal-browser/custom-auth";
Aggiungi la configurazione del client
In questa sezione viene definita una configurazione per l'applicazione client pubblica di autenticazione nativa per consentire l'interazione con l'interfaccia dell'SDK. A tale scopo, creare un file denominato src/config/auth-config.ts, quindi aggiungere il codice seguente:
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;
}
},
},
},
};
Nel codice, trova il segnaposto:
Enter_the_Application_Id_Heresostituirlo quindi con l'ID applicazione (client) dell'app registrata in precedenza.Enter_the_Tenant_Subdomain_Heresostituirlo quindi con il sottodominio tenant nell'interfaccia di amministrazione di Microsoft Entra. Ad esempio, se il dominio primario del tenant ècontoso.onmicrosoft.com, usarecontoso. Se non hai il nome del tuo locatario, scopri come leggere i dettagli del locatario.
Creare componenti dell'interfaccia utente
Questa app raccoglie i dettagli dell'utente, ad esempio il nome, il nome utente (indirizzo di posta elettronica), la password e un passcode monouso dell'utente. L'app deve quindi avere un modulo che raccoglie queste informazioni.
Creare una cartella denominata src/app/sign-up nella cartella src .
Creare il file sign-up/components/InitialForm.tsx , quindi incollare il codice da sign-up/components/InitialForm.tsx. Questo componente visualizza un modulo che raccoglie gli attributi di iscrizione utente.
Creare un file sign-up/components/CodeForm.tsx , quindi incollare il codice da sign-up/components/CodeForm.tsx. Questo componente visualizza un modulo che raccoglie un passcode monouso inviato all'utente. È necessario questo modulo per la posta elettronica con password o posta elettronica con metodo di autenticazione con passcode monouso.
Se la scelta del metodo di autenticazione è un messaggio di posta elettronica con password, creare un file di iscrizione/components/PasswordForm.tsx , quindi incollare il codice da sign-up/components/PasswordForm.tsx. Questo componente visualizza un modulo di input della password.
Gestione dell'interazione del modulo
In questa sezione viene aggiunto codice che gestisce le interazioni con i moduli di iscrizione, ad esempio l'invio dei dettagli di iscrizione utente o un passcode monouso o una password.
Crea sign-up/page.tsx per gestire la logica di un flusso di registrazione. In questo file:
Importare i componenti necessari e visualizzare il formato corretto in base allo stato. Consulta un esempio completo in sign-up/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> ); }Questo codice crea anche un'istanza dell'app client pubblico di autenticazione nativa utilizzando la configurazione del client:
const appInstance = await CustomAuthPublicClientApplication.create(customAuthConfig); setAuthClient(appInstance);Per gestire l'invio iniziale del modulo, usare il frammento di codice seguente. Per informazioni su dove inserire il frammento di codice, vedere un esempio completo all'indirizzo sign-up/page.tsx :
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); };Il metodo
signUp()di istanza dell'SDK avvia il flusso di iscrizione.Per gestire l'invio di passcode monouso, usare il frammento di codice seguente. Per informazioni su dove inserire il frammento di codice, vedere un esempio completo all'indirizzo sign-up/page.tsx :
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); } };Per gestire l'invio di password, usare il frammento di codice seguente. Gestisci l'invio di password se la tua scelta del metodo di autenticazione è la posta elettronica con password. Per informazioni su dove inserire il frammento di codice, vedere un esempio completo all'indirizzo sign-up/page.tsx :
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); };Usare
signUpState instanceof SignUpCompletedStateper indicare che l'utente è stato registrato e che il flusso è completo. Vedere un esempio completo all'indirizzo sign-up/page.tsx:if (signUpState instanceof SignUpCompletedState) { return <SignUpResultPage/>; }
Chiedere un nome utente (alias) durante l'iscrizione
È possibile consentire agli utenti di iscriversi con un nome utente (alias) oltre alla posta elettronica. Il nome utente (alias) è un identificatore di accesso alternativo, ad esempio un ID cliente, un numero di account o un altro valore scelto.
Durante l'iscrizione, il nome utente (indirizzo di posta elettronica) è sempre necessario come identificatore primario e il nome utente (alias) non lo sostituisce. Per impostazione predefinita, il nome utente (alias) è facoltativo, anche se un amministratore può configurarlo in base alle esigenze. L'app raccoglie sempre il nome utente (indirizzo di posta elettronica) e raccoglie l'alias come attributo insieme al messaggio di posta elettronica. All'accesso, l'utente può quindi accedere con il nome utente (indirizzo di posta elettronica) o il nome utente (alias). Per informazioni su come l'attributo Username è configurato come facoltativo o obbligatorio, vedere Configurare i tipi di input utente e il layout di pagina.
Per raccogliere un nome utente (alias) durante l'iscrizione:
Assicurarsi che l'attributo utente predefinito Username sia abilitato nel flusso utente di iscrizione. Per la procedura, vedere Abilitare il nome utente nei criteri di identificatore di accesso.
Aggiungi uno stato
flatUsernamealla pagina di registrazione, quindi includi l'attributoflatusernamenelUserAccountAttributesche passi asignUp():const [flatUsername, setFlatUsername] = useState(""); const attributes: UserAccountAttributes = { displayName: `${firstName} ${lastName}`, //... flatusername: flatUsername, };Aggiungere un campo alias a InitialForm.tsx per acquisire il valore del nome utente (alias):
<input type="text" placeholder="Username (alias)" value={flatUsername} onChange={(e) => setFlatUsername(e.target.value)} style={styles.input} />Gestire gli errori correlati al nome utente (alias):
-
result.error?.isUserAlreadyExists()copre un messaggio di posta elettronica duplicato o un nome utente duplicato (alias). Aggiornare il messaggio di conseguenza, ad esempio Un account con questo indirizzo di posta elettronica o nome utente esiste già. - Un nome utente (alias) non valido viene visualizzato tramite
result.error?.isAttributesValidationFailed()anziché tramiteresult.error?.isInvalidUsername(). Creare un ramo in questo metodo per visualizzare un messaggio specifico del nome utente.
-
Gestire gli errori di iscrizione
Durante l'iscrizione, non tutte le azioni hanno esito positivo. Ad esempio, l'utente potrebbe tentare di iscriversi con un indirizzo di posta elettronica già usato o inviare un passcode monouso di posta elettronica non valido. Assicurarsi di gestire correttamente gli errori quando:
Avvia la procedura di registrazione nel metodo
signUp().Invia il codice di verifica monouso nel metodo
submitCode().Invia la password nel metodo
submitPassword(). Gestisci questo errore se scegli un flusso di registrazione con email e password.
Uno degli errori che possono derivare dal signUp() metodo è result.error?.isRedirectRequired(). Questo scenario si verifica quando l'autenticazione nativa non è sufficiente per completare il flusso di autenticazione. Ad esempio, se il server di autorizzazione richiede funzionalità che il client non può fornire. Altre informazioni sul fallback Web di autenticazione nativa e su come supportare il fallback Web nell'app React.
Facoltativo: far accedere automaticamente gli utenti dopo la registrazione
Dopo l'iscrizione di un utente, è possibile accedere direttamente all'app senza avviare un nuovo flusso di accesso. A tale scopo, usare il frammento di codice seguente. Vedere un esempio completo all'indirizzo 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);
}
}
Eseguire e testare l'app
Aprire una finestra del terminale e passare alla cartella radice dell'app:
cd reactspaPer avviare il server proxy CORS, eseguire il comando seguente nel terminale:
npm run corsPer avviare l'app React, aprire un'altra finestra del terminale, quindi eseguire il comando seguente:
cd reactspa npm startAprire un Web browser e passare a
http://localhost:3000/sign-up. Viene visualizzato un modulo di iscrizione.Per iscriversi a un account, immettere i dettagli, selezionare il pulsante Continua e quindi seguire le istruzioni.
È quindi possibile aggiornare l'app React per accedere a un utente o reimpostare la password dell'utente.
Configurare poweredByHeader su false in next.config.js
Per impostazione predefinita, l'intestazione x-powered-by è inclusa nelle risposte HTTP per indicare che l'applicazione è basata su Next.js. Tuttavia, per motivi di sicurezza o personalizzazione, è possibile rimuovere o modificare questa intestazione:
const nextConfig: NextConfig = {
poweredByHeader: false,
/* other config options here */
};