Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Gilt für:
Externe Mandanten (weitere Informationen)
In diesem Lernprogramm erfahren Sie, wie Sie eine einzelseitige React-App erstellen, die Benutzer mithilfe der systemeigenen Authentifizierung registriert.
In diesem Tutorial führen Sie Folgendes durch:
- Erstellen Sie ein React-Projekt.
- Fügen Sie Ui-Komponenten der App hinzu.
- Richten Sie das Projekt ein, um den Benutzer mit Benutzername (E-Mail) und Kennwort zu registrieren.
Voraussetzungen
- Führen Sie die Schritte in der Schnellstartanleitung aus: Anmelden von Benutzern in einer React-Einzelseitenanwendung mithilfe der systemeigenen Authentifizierungs-API. In dieser Schnellstartanleitung erfahren Sie, wie Sie Ihren externen Mandanten vorbereiten und ein Beispiel für React-Code ausführen.
- Visual Studio Code oder ein anderer Code-Editor.
- Node.js
Erstellen eines React-Projekts und Installieren von Abhängigkeiten
Führen Sie an einem Speicherort ihrer Wahl auf Ihrem Computer die folgenden Befehle aus, um ein neues React-Projekt mit dem Namen reactspazu erstellen, navigieren Sie in den Projektordner, und installieren Sie dann Pakete:
npm config set legacy-peer-deps true
npx create-react-app reactspa --template typescript
cd reactspa
npm install ajv
npm install react-router-dom
npm install
Hinzufügen einer Konfigurationsdatei für Ihre App
Erstellen Sie eine Datei namens src/config.js, und fügen Sie dann den folgenden Code hinzu:
// App Id obatained from the Microsoft Entra portal
export const CLIENT_ID = "Enter_the_Application_Id_Here";
// URL of the CORS proxy server
const BASE_API_URL = `http://localhost:3001/api`;
// Endpoints URLs for Native Auth APIs
export const ENV = {
urlSignupStart: `${BASE_API_URL}/signup/v1.0/start`,
urlSignupChallenge: `${BASE_API_URL}/signup/v1.0/challenge`,
urlSignupContinue: `${BASE_API_URL}/signup/v1.0/continue`,
}
Suchen Sie den
Enter_the_Application_Id_HereWert, und ersetzen Sie ihn durch die Anwendungs-ID (clientId) der App, die Sie im Microsoft Entra Admin Center registriert haben.Die
BASE_API_URLverweist auf einen Cross-Origin Resource Sharing (CORS) Proxyserver, den wir später in dieser Tutorialreihe einrichten werden. Die systemeigene Authentifizierungs-API unterstützt CORS nicht. Daher richten wir einen CORS-Proxyserver zwischen React SPA und der nativen Authentifizierungs-API ein, um die CORS-Header zu verwalten.
Einrichten der React-App zum Aufrufen der nativen Authentifizierungs-API und Behandeln der Antwort
Zum Abschließen eines Authentifizierungsflows wie z. B. einem Anmeldeflow mit den nativen Authentifizierungs-APIs führt die App Aufrufe aus und verarbeitet die Antwort. Die App initiiert z. B. einen Registrierungsablauf und wartet auf eine Antwort und sendet dann Benutzerattribute und wartet erneut, bis der Benutzer erfolgreich registriert ist.
Einrichten des Clientaufrufs an die systemeigene Authentifizierungs-API
In diesem Abschnitt definieren Sie, wie Sie Aufrufe an die systemeigene Authentifizierung tätigen und Antworten behandeln:
Erstellen Sie einen Ordner namens client im src.
Erstellen Sie eine Datei namens scr/client/RequestClient.ts, und fügen Sie dann den folgenden Codeausschnitt hinzu:
import { ErrorResponseType } from "./ResponseTypes"; export const postRequest = async (url: string, payloadExt: any) => { const body = new URLSearchParams(payloadExt as any); const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body, }); if (!response.ok) { try { const errorData: ErrorResponseType = await response.json(); throw errorData; } catch (jsonError) { const errorData = { error: response.status, description: response.statusText, codes: [], timestamp: "", trace_id: "", correlation_id: "", }; throw errorData; } } return await response.json(); };Dieser Code definiert, wie die App Aufrufe an die systemeigene Authentifizierungs-API sendet und die Antworten verarbeitet. Wenn die App einen Authentifizierungsfluss initiieren muss, verwendet sie die
postRequest-Funktion, indem sie die URL- und Nutzlastdaten angibt.
Definieren von Aufrufen, die die App an die systemeigene Authentifizierungs-API sendet
Während des Registrierungsablaufs führt die App mehrere Aufrufe an die systemeigene Authentifizierungs-API durch.
Um diese Aufrufe zu definieren, erstellen Sie eine Datei namens scr/client/RequestTypes.ts, und fügen Sie dann den folgenden Codeausschnitt hinzu:
//SignUp
export interface SignUpStartRequest {
client_id: string;
username: string;
challenge_type: string;
password?: string;
attributes?: Object;
}
export interface SignUpChallengeRequest {
client_id: string;
continuation_token: string;
challenge_type?: string;
}
export interface SignUpFormPassword {
name: string;
surname: string;
username: string;
password: string;
}
//OTP
export interface ChallengeForm {
continuation_token: string;
oob?: string;
password?: string;
}
Definieren Sie die Art der Antworten, die die App von der nativen Authentifizierungs-API erhält.
Um den Typ der Antworten zu definieren, die die App von der systemeigenen Authentifizierungs-API für den Registrierungsvorgang erhalten kann, erstellen Sie eine Datei namens src/client/ResponseTypes.ts, und fügen Sie dann den folgenden Codeausschnitt hinzu:
export interface SuccessResponseType {
continuation_token?: string;
challenge_type?: string;
}
export interface ErrorResponseType {
error: string;
error_description: string;
error_codes: number[];
timestamp: string;
trace_id: string;
correlation_id: string;
}
export interface ChallengeResponse {
binding_method: string;
challenge_channel: string;
challenge_target_label: string;
challenge_type: string;
code_length: number;
continuation_token: string;
interval: number;
}
Verarbeiten der Registrierungsanforderungen
In diesem Abschnitt fügen Sie Code hinzu, der Registrierungsflussanforderungen verarbeitet. Beispiele für diese Anfragen sind das Starten eines Registrierungsablaufs, das Auswählen einer Authentifizierungsmethode und das Senden eines Einmalkennworts.
Erstellen Sie dazu eine Datei namens src/client/SignUpService.ts, und fügen Sie dann den folgenden Codeausschnitt hinzu:
import { CLIENT_ID, ENV } from "../config";
import { postRequest } from "./RequestClient";
import { ChallengeForm, SignUpChallengeRequest, SignUpFormPassword, SignUpStartRequest } from "./RequestTypes";
import { ChallengeResponse } from "./ResponseTypes";
//handle start a sign-up flow
export const signupStart = async (payload: SignUpFormPassword) => {
const payloadExt: SignUpStartRequest = {
attributes: JSON.stringify({
given_name: payload.name,
surname: payload.surname,
}),
username: payload.username,
password: payload.password,
client_id: CLIENT_ID,
challenge_type: "password oob redirect",
};
return await postRequest(ENV.urlSignupStart, payloadExt);
};
//handle selecting an authentication method
export const signupChallenge = async (payload: ChallengeForm):Promise<ChallengeResponse> => {
const payloadExt: SignUpChallengeRequest = {
client_id: CLIENT_ID,
challenge_type: "password oob redirect",
continuation_token: payload.continuation_token,
};
return await postRequest(ENV.urlSignupChallenge, payloadExt);
};
//handle submit one-time passcode
export const signUpSubmitOTP = async (payload: ChallengeForm) => {
const payloadExt = {
client_id: CLIENT_ID,
continuation_token: payload.continuation_token,
oob: payload.oob,
grant_type: "oob",
};
return await postRequest(ENV.urlSignupContinue, payloadExt);
};
Die challenge_type-Eigenschaft zeigt die Authentifizierungsmethoden an, die von der Client-App unterstützt werden. Diese App signiert per E-Mail mit Kennwort. Daher ist der Aufforderungstyp Out-Of-Band-Umleitung mit Kennwort. Weitere Informationen finden Sie unter Aufforderungstypen.
Erstellen von UI-Komponenten
Diese App sammelt Benutzerdetails wie Vorname, Benutzername (E-Mail) und Kennwort sowie eine Einmalkennung des Benutzers. Daher muss die App über eine Registrierung und ein einmaliges Kennungssammlungsformular verfügen.
Erstellen Sie einen Ordner namens /pages/SignUp im ordner src.
Um das Registrierungsformular zu erstellen, anzuzeigen und zu übermitteln, erstellen Sie eine Datei src/pages/SignUp/SignUp.tsx, und fügen Sie dann den folgenden Code hinzu:
import React, { useState } from 'react'; import { signupChallenge, signupStart } from '../../client/SignUpService'; import { useNavigate } from 'react-router-dom'; import { ErrorResponseType } from "../../client/ResponseTypes"; export const SignUp: React.FC = () => { const [name, setName] = useState<string>(''); const [surname, setSurname] = useState<string>(''); const [email, setEmail] = useState<string>(''); const [error, setError] = useState<string>(''); const [isLoading, setIsloading] = useState<boolean>(false); const navigate = useNavigate(); const validateEmail = (email: string): boolean => { const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return re.test(String(email).toLowerCase()); }; const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); if (!name || !surname || !email) { setError('All fields are required'); return; } if (!validateEmail(email)) { setError('Invalid email format'); return; } setError(''); try { setIsloading(true); const res1 = await signupStart({ name, surname, username: email, password }); const res2 = await signupChallenge({ continuation_token: res1.continuation_token }); navigate('/signup/challenge', { state: { ...res2} }); } catch (err) { setError("An error occurred during sign up " + (err as ErrorResponseType).error_description); } finally { setIsloading(false); } }; return ( <div className="sign-up-form"> <form onSubmit={handleSubmit}> <h2>Sign Up</h2> <div className="form-group"> <label>Name:</label> <input type="text" value={name} onChange={(e) => setName(e.target.value)} required /> </div> <div className="form-group"> <label>Last Name:</label> <input type="text" value={surname} onChange={(e) => setSurname(e.target.value)} required /> </div> <div className="form-group"> <label>Email:</label> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required /> </div> {error && <div className="error">{error}</div>} {isLoading && <div className="warning">Sending request...</div>} <button type="submit">Sign Up</button> </form> </div> ); };Um das einmalige Kennungsformular zu erstellen, anzuzeigen und zu übermitteln, erstellen Sie eine Datei src/pages/signup/SignUpChallenge.tsx, und fügen Sie dann den folgenden Code hinzu:
import React, { useState } from "react"; import { useNavigate, useLocation } from "react-router-dom"; import { signUpSubmitOTP } from "../../client/SignUpService"; import { ErrorResponseType } from "../../client/ResponseTypes"; export const SignUpChallenge: React.FC = () => { const { state } = useLocation(); const navigate = useNavigate(); const { challenge_target_label, challenge_type, continuation_token, code_length } = state; const [code, setCode] = useState<string>(""); const [error, setError] = useState<string>(""); const [isLoading, setIsloading] = useState<boolean>(false); const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); if (!code) { setError("All fields are required"); return; } setError(""); try { setIsloading(true); const res = await signUpSubmitOTP({ continuation_token, oob: code }); navigate("/signup/completed"); } catch (err) { setError("An error occurred during sign up " + (err as ErrorResponseType).error_description); } finally { setIsloading(false); } }; return ( <div className="sign-up-form"> <form onSubmit={handleSubmit}> <h2>Insert your one time code received at {challenge_target_label}</h2> <div className="form-group"> <label>Code:</label> <input maxLength={code_length} type="text" value={code} onChange={(e) => setCode(e.target.value)} required /> </div> {error && <div className="error">{error}</div>} {isLoading && <div className="warning">Sending request...</div>} <button type="submit">Sign Up</button> </form> </div> ); };Erstellen Sie eine Datei src/pages/signup/SignUpCompleted.tsx, und fügen Sie dann den folgenden Code hinzu:
import React from 'react'; import { Link } from 'react-router-dom'; export const SignUpCompleted: React.FC = () => { return ( <div className="sign-up-completed"> <h2>Sign Up Completed</h2> <p>Your sign-up process is complete. You can now log in.</p> <Link to="/signin" className="login-link">Go to Login</Link> </div> ); };Auf dieser Seite wird eine Erfolgsmeldung und eine Schaltfläche angezeigt, über die der Benutzer zur Anmeldeseite gelangen kann, nachdem er sich erfolgreich angemeldet hat.
Öffnen Sie die datei src/App.tsx, und ersetzen Sie den Inhalt durch den folgenden Code:
import React from "react"; import { BrowserRouter, Link } from "react-router-dom"; import "./App.css"; import { AppRoutes } from "./AppRoutes"; function App() { return ( <div className="App"> <BrowserRouter> <header> <nav> <ul> <li> <Link to="/signup">Sign Up</Link> </li> <li> <Link to="/signin">Sign In</Link> </li> <li> <Link to="/reset">Reset Password</Link> </li> </ul> </nav> </header> <AppRoutes /> </BrowserRouter> </div> ); } export default App;So zeigen Sie die React-App ordnungsgemäß an:
Öffnen Sie die datei src/App.css, und fügen Sie dann die folgende Eigenschaft in der
App-header-Klasse hinzu:min-height: 100vh;Öffnen Sie die datei src/Index.css, und ersetzen Sie dann den Inhalt durch Code aus src/index.css
Hinzufügen von App-Routen
Erstellen Sie eine Datei namens src/AppRoutes.tsx, und fügen Sie dann den folgenden Code hinzu:
import { Route, Routes } from "react-router-dom";
import { SignUp } from "./pages/SignUp/SignUp";
import { SignUpChallenge } from "./pages/SignUp/SignUpChallenge";
import { SignUpCompleted } from "./pages/SignUp/SignUpCompleted";
export const AppRoutes = () => {
return (
<Routes>
<Route path="/" element={<SignUp />} />
<Route path="/signup" element={<SignUp />} />
<Route path="/signup/challenge" element={<SignUpChallenge />} />
<Route path="/signup/completed" element={<SignUpCompleted />} />
</Routes>
);
};
An diesem Punkt kann Ihre React-App Anmeldeanforderungen an die systemeigene Authentifizierungs-API senden, aber wir müssen den CORS-Proxyserver einrichten, um die CORS-Header zu verwalten.