Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Van toepassing op: Werknemerstenants
Externe tenants (meer informatie)
In deze zelfstudie leert u hoe u een React-app met één pagina bouwt waarmee gebruikers worden geregistreerd met behulp van systeemeigen verificatie.
In deze handleiding leert u:
- Een React-project maken.
- Ui-onderdelen van de app toevoegen.
- Stel het project in om de gebruiker te registreren met behulp van gebruikersnaam (e-mailadres) en wachtwoord.
Voorwaarden
- Voltooi de stappen in quickstart: Gebruikers aanmelden in een react-voorbeeldtoepassing met één pagina met behulp van de systeemeigen verificatie-API. In deze quickstart ziet u hoe u uw externe tenant voorbereidt en een voorbeeld van React-codevoorbeeld uitvoert.
- Visual Studio Code of een andere code-editor.
- Node.js.
Een React-project maken en afhankelijkheden installeren
Voer op een locatie naar keuze op uw computer de volgende opdrachten uit om een nieuw React-project te maken met de naam reactspa, navigeer naar de projectmap en installeer vervolgens pakketten:
npm config set legacy-peer-deps true
npx create-react-app reactspa --template typescript
cd reactspa
npm install ajv
npm installreact-router-dom
npm install
Configuratiebestand voor uw app toevoegen
Maak een bestand met de naam src/config.jsen voeg vervolgens de volgende code toe:
// 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`,
}
Zoek de
Enter_the_Application_Id_Here
waarde en vervang deze door de toepassings-id (clientId) van de app die u hebt geregistreerd in het Microsoft Entra-beheercentrum.De
BASE_API_URL
verwijst naar een CORS-proxyserver (Cross-Origin Resource Sharing), die we verderop in deze reeks zelfstudies hebben ingesteld. Systeemeigen verificatie-API biedt geen ondersteuning voor CORS, dus we hebben een CORS-proxyserver ingesteld tussen de React SPA en de systeemeigen verificatie-API voor het beheren van de CORS-headers.
React-app instellen om systeemeigen verificatie-API aan te roepen en antwoord af te handelen
Voor het voltooien van een authenticatieproces, zoals een aanmeldprocedure, met de systeemeigen verificatie-API's, maakt de app oproepen en verwerkt het antwoord. De app initieert bijvoorbeeld een registratiestroom en wacht op een antwoord. Vervolgens worden gebruikerskenmerken verzonden en wordt er opnieuw gewacht totdat de gebruiker is aangemeld.
Clientoproep instellen voor de systeemeigen verificatie-API
In deze sectie definieert u hoe u aanroepen uitvoert naar de systeemeigen verificatie en antwoorden verwerkt:
Maak een map met de naam client in de src.
Maak een bestand met de naam scr/client/RequestClient.ts en voeg vervolgens het volgende codefragment toe:
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(); };
Deze code definieert hoe de app aanroept naar de systeemeigen verificatie-API en hoe de antwoorden worden verwerkt. Wanneer de app een verificatiestroom moet initiëren, wordt de functie
postRequest
gebruikt door de URL- en nettoladinggegevens op te geven.
Typen aanroepen definiëren die door de app worden uitgevoerd naar de systeemeigen verificatie-API
Tijdens de registratiestroom voert de app meerdere aanroepen uit naar de systeemeigen verificatie-API.
Als u deze aanroepen wilt definiëren, maakt u een bestand met de naam scr/client/RequestTypes.ts en voegt u vervolgens het volgende codefragment toe:
//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;
}
Het type antwoorden definiëren dat de app ontvangt van de systeemeigen verificatie-API
Als u het type antwoorden wilt definiëren dat de app kan ontvangen van de systeemeigen verificatie-API voor de registratiebewerking, maakt u een bestand met de naam src/client/ResponseTypes.ts en voegt u vervolgens het volgende codefragment toe:
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;
}
Registratieaanvragen verwerken
In deze sectie voegt u code toe waarmee registratiestroomaanvragen worden verwerkt. Voorbeelden van deze aanvragen zijn het starten van een registratiestroom, het selecteren van een verificatiemethode en het verzenden van een eenmalige wachtwoordcode.
Maak hiervoor een bestand met de naam src/client/SignUpService.ts en voeg vervolgens het volgende codefragment toe:
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);
};
De eigenschap challenge_type
toont de verificatiemethoden die door de client-app worden ondersteund. Deze app meldt zich aan met e-mail en wachtwoord, dus de waarde van het vraagtype is wachtwoord oob-omleiding. Lees meer over uitdagingstypen.
UI-onderdelen maken
Deze app verzamelt gebruikersgegevens, zoals de opgegeven naam, achternaam (e-mail) en het wachtwoord en een eenmalige wachtwoordcode van de gebruiker. De app moet dus een registratie- en een eenmalige verzamelingsformulier voor wachtwoordcodes hebben.
Maak een map met de naam /pages/SignUp in de src-map .
Als u het registratieformulier wilt maken, weergeven en verzenden, maakt u een bestand src/pages/SignUp/SignUp.tsx en voegt u de volgende code toe:
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> ); };
Als u het eenmalige wachtwoordcodeformulier wilt maken, weergeven en verzenden, maakt u een bestand src/pages/signup/SignUpChallenge.tsx en voegt u de volgende code toe:
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> ); };
Maak een bestand src/pages/signup/SignUpCompleted.tsx en voeg vervolgens de volgende code toe:
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> ); };
Op deze pagina wordt een bericht met succes en een knop weergegeven om de gebruiker naar de aanmeldingspagina te brengen nadat deze zich heeft geregistreerd.
Open het bestand src/App.tsx en vervang de inhoud door de volgende 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;
De React-app correct weergeven:
Open het bestand src/App.css en voeg vervolgens de volgende eigenschap toe in de
App-header
klasse:min-height: 100vh;
Open het bestand src/Index.css en vervang de inhoud door code uit src/index.css
App-routes toevoegen
Maak een bestand met de naam src/AppRoutes.tsx en voeg de volgende code toe:
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>
);
};
Op dit moment kan uw React-app registratieaanvragen verzenden naar de systeemeigen verificatie-API, maar we moeten de CORS-proxyserver instellen om de CORS-headers te beheren.