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: Werkplekhuren
Externe huurders (meer informatie)
In deze zelfstudie leert u hoe u gebruikers kunt aanmelden bij een React-app met één pagina (SPA) met behulp van systeemeigen verificatie.
In deze handleiding leert u:
- Werk de React-app bij om gebruikers aan te melden met gebruikersnaam(e-mailadres) en wachtwoord.
- Aanmeldingsstroom testen.
Voorwaarden
- Voltooi de stappen in Tutorial: CORS-proxyserver instellen om CORS-headers te beheren voor native authenticatie.
Typen aanroepen definiëren die door de app worden uitgevoerd naar de systeemeigen verificatie-API
Tijdens de aanmeldingsstroom voert de app meerdere aanroepen uit naar de systeemeigen verificatie-API, zoals het starten van een aanmeldingsaanvraag, het selecteren van een verificatiemethode en het aanvragen van beveiligingstokens.
Als u deze aanroepen wilt definiëren, opent u het bestand scr/client/RequestTypes.ts en voegt u het volgende codefragment toe:
export interface TokenRequestType {
continuation_token: string;
client_id: string;
grant_type: string;
scope: string;
password?: string;
oob?: string;
challenge_type?: string;
}
// Sign in
export interface TokenSignInType {
continuation_token: string;
grant_type: string;
password?: string;
oob?: string;
}
export interface ChallengeRequest {
client_id: string;
challenge_type: string;
continuation_token: string;
}
export interface SignInStartRequest {
client_id: string;
challenge_type: string;
username: string;
}
export interface SignInTokenRequest {
client_id: string;
grant_type: string;
continuation_token: string;
scope: string;
challenge_type?: string;
password?: string;
oob?: 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 aanmeldingsbewerking, opent u het bestand src/client/ResponseTypes.ts en voegt u vervolgens het volgende codefragment toe:
export interface TokenResponseType {
token_type: string;
scope: string;
expires_in: number;
access_token: string;
refresh_token: string;
id_token: string;
}
Aanmeldingsaanvragen verwerken
In deze sectie voegt u code toe waarmee aanmeldingsstroomaanvragen worden verwerkt. Voorbeelden van deze aanvragen zijn het starten van een aanmeldingsstroom, het selecteren van een verificatiemethode of het aanvragen van een beveiligingstoken.
Hiervoor maakt u een bestand met de naam src/client/SignInService.tsen voegt u het volgende codefragment toe:
import { CLIENT_ID, ENV } from "../config";
import { postRequest } from "./RequestClient";
import { ChallengeRequest, SignInStartRequest, TokenRequestType, TokenSignInType } from "./RequestTypes";
import { TokenResponseType } from "./ResponseTypes";
export const signInStart = async ({ username }: { username: string }) => {
const payloadExt: SignInStartRequest = {
username,
client_id: CLIENT_ID,
challenge_type: "password oob redirect",
};
return await postRequest(ENV.urlOauthInit, payloadExt);
};
export const signInChallenge = async ({ continuation_token }: { continuation_token: string }) => {
const payloadExt: ChallengeRequest = {
continuation_token,
client_id: CLIENT_ID,
challenge_type: "password oob redirect",
};
return await postRequest(ENV.urlOauthChallenge, payloadExt);
};
export const signInTokenRequest = async (request: TokenSignInType): Promise<TokenResponseType> => {
const payloadExt: TokenRequestType = {
...request,
client_id: CLIENT_ID,
challenge_type: "password oob redirect",
scope: "openid offline_access",
};
if (request.grant_type === "password") {
payloadExt.password = request.password;
}
if (request.grant_type === "oob") {
payloadExt.oob = request.oob;
}
return await postRequest(ENV.urlOauthToken, payloadExt);
};
De eigenschap challenge_type
toont de verificatiemethoden die door de client-app worden ondersteund. Deze app maakt gebruik van e-mail met wachtwoord voor aanmelding, dus de waarde van het vraagtype is wachtwoord oob-omleiding. Lees meer over uitdagingstypen.
UI-onderdelen maken
Tijdens het aanmeldingsproces verzamelt deze app de inloggegevens van de gebruiker, waaronder hun gebruikersnaam (e-mailadres) en wachtwoord, om de gebruiker aan te melden. Nadat de gebruiker zich heeft aangemeld, worden de gegevens van de gebruiker weergegeven in de app.
Maak een map met de naam /pages/signin in de map src.
Als u het aanmeldingsformulier wilt maken, weergeven en verzenden, maakt u een bestand src/pages/signin/SignIn.tsxen voegt u de volgende code toe:
import React, { useState } from "react"; import { Link as LinkTo, useNavigate } from "react-router-dom"; import { signInStart, signInChallenge, signInTokenRequest } from "../../client/SignInService"; import { ErrorResponseType } from "../../client/ResponseTypes"; export const SignIn: React.FC = () => { const [email, setEmail] = useState<string>(""); const [password, setPassword] = 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 (!validateEmail(email)) { setError("Invalid email format"); return; } setError(""); setIsloading(true); try { const res1 = await signInStart({ username: email, }); const res2 = await signInChallenge({ continuation_token: res1.continuation_token }); const res3 = await signInTokenRequest({ continuation_token: res2.continuation_token, grant_type: "password", password: password, }); navigate("/user", { state: res3 }); } catch (err) { setError("An error has occured " + (err as ErrorResponseType).error_description); } finally { setIsloading(false); } }; return ( <div className="login-form"> <form onSubmit={handleSubmit}> <h2>Login</h2> <div className="form-group"> <label>Email:</label> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required /> </div> <div className="form-group"> <label>Password:</label> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} required /> </div> {error && <div className="error">{error}</div>} {isLoading && <div className="warning">Sending request...</div>} <button type="submit" disabled={isLoading}>Login</button> </form> </div> ); };
De details van de gebruiker weergeven na een geslaagde aanmelding:
Maak een bestand met de naam client/Utils.tsen voeg vervolgens het volgende codefragment toe:
export function parseJwt(token: string) { var base64Url = token.split(".")[1]; var base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/"); var jsonPayload = decodeURIComponent( window .atob(base64) .split("") .map(function (c) { return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); }) .join("") ); return JSON.parse(jsonPayload); }
Maak een map met de naam gebruiker in de map src/pages.
Maak een bestand met de naam src/pages/user/UserInfo.tsxen voeg vervolgens het volgende codefragment toe:
// User.tsx import React from "react"; import { useLocation } from "react-router-dom"; import { parseJwt } from "../../client/Utils"; export const UserInfo: React.FC = () => { const { state } = useLocation(); const decodedToken = parseJwt(state.access_token); const { given_name, scp, family_name, unique_name: email } = decodedToken; console.log(decodedToken); const familyName = family_name; const givenName = given_name; const tokenExpireTime = state.expires_in; const scopes = state.scope; return ( <div className="user-info"> <h2>User Information</h2> <div className="info-group"> <label>Given Name:</label> <span>{givenName}</span> </div> <div className="info-group"> <label>Family Name:</label> <span>{familyName}</span> </div> <div className="info-group"> <label>Email:</label> <span>{email}</span> </div> <div className="info-group"> <label>Token Expire Time:</label> <span>{tokenExpireTime}</span> </div> <div className="info-group"> <label>Scopes:</label> <span>{scopes}</span> </div> <div className="info-group"> <label>Token payload:</label> <span><pre>{JSON.stringify(decodedToken, null, 2)}</pre></span> </div> </div> ); };
App-routes toevoegen
Open het bestand src/AppRoutes.tsx en vervang de inhoud door de volgende code:
import { Route, Routes } from "react-router-dom";
import { SignIn } from "./pages/SignIn/SignIn";
import { UserInfo } from "./pages/User/UserInfo";
import { SignUp } from "./pages/SignUp/SignUp";
import { SignUpChallenge } from "./pages/SignUp/SignUpChallenge";
import { SignUpCompleted } from "./pages/SignUp/SignUpCompleted";
//For password reset
//import { ResetPassword } from "./pages/ResetAccount/ResetPassword";
export const AppRoutes = () => {
return (
<Routes>
<Route path="/" element={<SignUp />} />
<Route path="/signin" element={<SignIn />} />
<Route path="/user" element={<UserInfo />} />
<Route path="/signup" element={<SignUp />} />
<Route path="/signup/challenge" element={<SignUpChallenge />} />
<Route path="/signup/completed" element={<SignUpCompleted />} />
//For password reset
//<Route path="/reset" element={<ResetPassword />} />
</Routes>
);
};
Uw app uitvoeren en testen
Gebruik de stappen in De app uitvoeren en testen om uw app uit te voeren, maar test deze keer het aanmeldproces met het gebruikersaccount dat u eerder registreerde.