Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Gäller för:
Workforce-hyresgäster
externa hyresgäster (läs mer)
I den här självstudien får du lära dig hur du skapar en React-ensidesapp som registrerar användare med inbyggd autentisering.
I den här handledningen kommer du att:
- Skapa ett React-projekt.
- Lägg till UI-komponenter i appen.
- Konfigurera projektet för att registrera användare med användarnamn (e-post) och lösenord.
Förutsättningar
- Slutför stegen i Snabbstart: Logga in användare i ett exempel på react-ensidesprogram med hjälp av api för intern autentisering. Den här snabbstarten visar hur du förbereder din externa hyresgäst och kör ett React-kodexempel.
- Visual Studio Code eller någon annan kodredigerare.
- Node.js.
Skapa ett React-projekt och installera beroenden
På en valfri plats på datorn kör du följande kommandon för att skapa ett nytt React-projekt med namnet reactspa, navigera till projektmappen och installera paket:
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
Lägga till konfigurationsfil för din app
Skapa en fil med namnet src/config.jsoch lägg sedan till följande kod:
// 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`,
}
Leta reda på värdet
Enter_the_Application_Id_Hereoch ersätt det med Application ID (clientId) för appen som du registrerade i administrationscentret för Microsoft Entra.BASE_API_URLpekar på en CORS (Cross-Origin Resource Sharing) proxyserver, som vi konfigurerade senare i den här självstudieserien. Api för intern autentisering stöder inte CORS, så vi konfigurerar en CORS-proxyserver mellan React SPA och API:et för intern autentisering för att hantera CORS-huvudena.
Konfigurera React-appen för att anropa api för intern autentisering och hantera svar
För att slutföra ett autentiseringsflöde, till exempel ett registreringsflöde, med api:erna för intern autentisering, gör appen calla dn hanterar svar. Appen initierar till exempel ett registreringsflöde och väntar på ett svar och skickar sedan användarattribut och väntar igen tills användaren har registrerat sig.
Konfigurera klientanrop till det interna autentiserings-API:et
I det här avsnittet definierar du hur du gör anrop till den interna autentiseringen och hanterar svar:
Skapa en mapp med namnet klient i src-.
Skapa en fil med namnet scr/client/RequestClient.tsoch lägg sedan till följande kodfragment:
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(); };Den här koden definierar hur appen anropar det interna autentiserings-API:et och hanterar svaren. När appen behöver initiera ett autentiseringsflöde använder den funktionen
postRequestgenom att ange URL:en och nyttolastdata.
Definiera typer av anrop som appen gör till det interna autentiserings-API:et
Under registreringsflödet gör appen flera anrop till det interna autentiserings-API:et.
Om du vill definiera dessa anrop skapar du en fil med namnet scr/client/RequestTypes.tsoch lägger sedan till följande kodfragment:
//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;
}
Definiera vilken typ av svar appen tar emot från det interna autentiserings-API:et
Om du vill definiera vilken typ av svar appen kan ta emot från det interna autentiserings-API:et för registreringsåtgärden skapar du en fil med namnet src/client/ResponseTypes.tsoch lägger sedan till följande kodfragment:
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;
}
Bearbeta registreringsbegäranden
I det här avsnittet lägger du till kod som bearbetar begäranden om registreringsflöde. Exempel på dessa begäranden är att starta ett registreringsflöde, välja en autentiseringsmetod och skicka ett engångslösenord.
Om du vill göra det skapar du en fil med namnet src/client/SignUpService.tsoch lägger sedan till följande kodfragment:
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);
};
Egenskapen challenge_type visar de autentiseringsmetoder som klientappen stöder. Den här appskylten använder e-post med lösenord, så värdet för utmaningstypen är omdirigering av lösenord. Läs mer om utmaningstyper.
Skapa gränssnittskomponenter
Den här appen samlar in användarinformation som förnamn, användarnamn (e-post) och lösenord och ett engångslösenord från användaren. Därför måste appen ha ett registreringsformulär och ett engångsformulär för lösenordsinsamling.
Skapa en mapp med namnet /pages/SignUp i mappen src.
Om du vill skapa, visa och skicka registreringsformuläret skapar du en fil src/pages/SignUp/SignUp.tsxoch lägger sedan till följande kod:
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> ); };Om du vill skapa, visa och skicka engångslösenordsformuläret skapar du en fil src/pages/signup/SignUpChallenge.tsxoch lägger sedan till följande kod:
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> ); };Skapa en fil src/pages/signup/SignUpCompleted.tsxoch lägg sedan till följande kod:
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> ); };Den här sidan visar ett meddelande om lyckat resultat och en knapp för att ta användaren till inloggningssidan när de har registrerat sig.
Öppna filen src/App.tsx och ersätt innehållet med följande kod:
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;Så här visar du React-appen korrekt:
Öppna filen src/App.css och lägg sedan till följande egenskap i klassen
App-header:min-height: 100vh;Öppna filen src/Index.css och ersätt innehållet med kod från src/index.css
Lägga till appvägar
Skapa en fil med namnet src/AppRoutes.tsxoch lägg sedan till följande kod:
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>
);
};
Din React-app kan nu skicka registreringsbegäranden till det interna autentiserings-API:et, men vi måste konfigurera CORS-proxyservern för att hantera CORS-huvudena.