Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Platí pro:
Externí nájemci (další informace)
V tomto kurzu se dozvíte, jak vytvořit jednostráňovou aplikaci React, která zaregistruje uživatele pomocí nativního ověřování.
V tomto kurzu se naučíte:
- Vytvořte projekt React.
- Přidejte součásti uživatelského rozhraní aplikace.
- Nastavte projekt pro registraci uživatele pomocí uživatelského jména (e-mailu) a hesla.
Požadavky
- Dokončete kroky v Rychlém startu: Přihlášení uživatelů do ukázkové jednostránkové aplikace React pomocí API pro nativní ověřování. V tomto rychlém startu se dozvíte, jak připravit externího tenanta a spustit ukázkovou ukázku kódu React.
- Visual Studio Code nebo jiný kódový editor.
- Node.js.
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:
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
Přidání konfiguračního souboru pro aplikaci
Vytvořte soubor s názvem src/config.jsa přidejte následující kód:
// 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`,
}
Najděte hodnotu
Enter_the_Application_Id_Herea nahraďte ji ID aplikace (clientId) aplikace, kterou jste zaregistrovali v Centru pro správu Entra.BASE_API_URLodkazuje na sdílení prostředků mezi různými zdroji (CORS) proxy server, který později nastavíme v této sérii kurzů. Nativní rozhraní API pro ověřování nepodporuje CORS, proto jsme nastavili proxy server CORS mezi react SPA a nativním ověřovacím rozhraním API pro správu hlaviček CORS.
Nastavení aplikace React pro volání nativního rozhraní API pro ověřování a zpracování odpovědi
Aby aplikace dokončila proces ověřování, jako je například proces registrace, s využitím nativních ověřovacích API, provádí volání a zpracovává odpověď. Aplikace například zahájí tok registrace a počká na odpověď a pak odešle atributy uživatele a počká znovu, dokud se uživatel úspěšně nezaregistruje.
Nastavení volání klienta do nativního rozhraní API pro ověřování
V této části definujete, jak provádět volání nativního ověřování a zpracovávat odpovědi:
Vytvořte složku s názvem client ve složce src.
Vytvořte soubor s názvem scr/client/RequestClient.tsa přidejte následující fragment kódu:
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(); };Tento kód definuje, jak aplikace volá nativní rozhraní API pro ověřování a zpracovává odpovědi. Pokaždé, když aplikace potřebuje zahájit ověřovací tok, použije funkci
postRequestzadáním adresy URL a dat datové části.
Definování typů volání, která aplikace provede do nativního ověřovacího rozhraní API
Během procesu registrace aplikace provádí více volání do nativního ověřovacího rozhraní API.
Pokud chcete definovat tato volání, vytvořte soubor s názvem scr/client/RequestTypes.tsa pak přidejte následující fragment kódu:
//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;
}
Definování typu aplikace odpovědí, která přijímá z nativního rozhraní API pro ověřování
Pokud chcete definovat typ odpovědí, které aplikace může přijímat z nativního ověřovacího rozhraní API pro operaci registrace, vytvořte soubor s názvem src/client/ResponseTypes.tsa přidejte následující fragment kódu:
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;
}
Zpracování žádostí o registraci
V této části přidáte kód, který zpracovává požadavky na proces registrace. Příkladem těchto požadavků je spuštění toku registrace, výběr metody ověřování a odeslání jednorázového hesla.
Uděláte to tak, že vytvoříte soubor s názvem src/client/SignUpService.tsa pak přidáte následující fragment kódu:
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);
};
Vlastnost challenge_type zobrazuje metody ověřování, které klientská aplikace podporuje. Tato aplikace používá e-mail s heslem, takže hodnota typu výzvy je přesměrování hesla. Přečtěte si další informace o výzvách typu.
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) a heslo a jednorázové heslo od uživatele. Aplikace tedy musí mít registrační formulář a jednorázový formulář pro shromažďování hesla.
Vytvořte složku s názvem /pages/SignUp ve složce src.
Pokud chcete vytvořit, zobrazit a odeslat registrační formulář, vytvořte soubor src/pages/SignUp.tsxa přidejte následující kód:
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> ); };Pokud chcete vytvořit, zobrazit a odeslat formulář jednorázového hesla, vytvořte soubor src/pages/signup/SignUpChallenge.tsxa pak přidejte následující kód:
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> ); };Vytvořte soubor src/pages/signup/SignUpCompleted.tsxa přidejte následující kód:
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> ); };Na této stránce se zobrazí zpráva o úspěchu a tlačítko, které uživatele po úspěšné registraci převeze na přihlašovací stránku.
Otevřete soubor src/App.tsx a nahraďte jeho obsah následujícím kódem:
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;Správné zobrazení aplikace React:
Otevřete soubor src/App.css a do třídy
App-headerpřidejte následující vlastnost:min-height: 100vh;Otevřete soubor src/Index.css a nahraďte jeho obsah kódem z src/index.css
Přidání tras aplikací
Vytvořte soubor s názvem src/AppRoutes.tsxa přidejte následující kód:
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>
);
};
V tuto chvíli může vaše aplikace React odesílat žádosti o registraci do nativního ověřovacího rozhraní API, ale potřebujeme nastavit proxy server CORS pro správu hlaviček CORS.