Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Se aplica a: inquilinos de personal
inquilinos externos (más información)
En este tutorial, aprenderá a iniciar sesión de los usuarios en una aplicación de página única (SPA) de React mediante la autenticación nativa.
En este tutorial, harás lo siguiente:
- Actualice la aplicación React para iniciar sesión de los usuarios con nombre de usuario (correo electrónico) y contraseña.
- Pruebe el flujo de inicio de sesión.
Prerrequisitos
- Complete los pasos descritos en Tutorial: Configuración del servidor proxy de CORS para administrar encabezados CORS para la autenticación nativa.
Definición de tipos de llamadas que realiza la aplicación a la API de autenticación nativa
Durante el flujo de inicio de sesión, la aplicación realiza varias llamadas a la API de autenticación nativa, como iniciar una solicitud de inicio de sesión, seleccionar un método de autenticación y solicitar tokens de seguridad.
Para definir estas llamadas, abra el archivo scr/client/RequestTypes.ts y, a continuación, anexe el siguiente fragmento de código:
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;
}
Definición del tipo de respuestas que la aplicación recibe de la API de autenticación nativa
Para definir el tipo de respuestas que la aplicación puede recibir de la API de autenticación nativa para la operación de inicio de sesión, abra el archivo src/client/ResponseTypes.ts y, a continuación, anexe el siguiente fragmento de código:
export interface TokenResponseType {
token_type: string;
scope: string;
expires_in: number;
access_token: string;
refresh_token: string;
id_token: string;
}
Procesar solicitudes de inicio de sesión
En esta sección, agregará código que procesa las solicitudes del proceso de inicio de sesión. Algunos ejemplos de estas solicitudes son iniciar un flujo de inicio de sesión, seleccionar un método de autenticación o solicitar un token de seguridad.
Para ello, cree un archivo denominado src/client/SignInService.tsy agregue el siguiente fragmento de código:
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);
};
La propiedad challenge_type
muestra los métodos de autenticación que admite la aplicación cliente. Esta aplicación utiliza el correo electrónico con contraseña para iniciar sesión, por lo que el valor del tipo de desafío es redirección de contraseña fuera de banda. Lea más sobre los tipos de desafío .
Creación de componentes de interfaz de usuario
Durante el flujo de inicio de sesión, esta aplicación recopila las credenciales del usuario, el nombre de usuario (correo electrónico) y la contraseña para iniciar sesión en el usuario. Una vez que el usuario inicie sesión correctamente, la aplicación muestra los detalles del usuario.
Cree una carpeta denominada /pages/signin en la carpeta src.
Para crear, mostrar y enviar el formulario de inicio de sesión, cree un archivo src/pages/signin/SignIn.tsxy agregue el código siguiente:
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> ); };
Para mostrar los detalles del usuario después de un inicio de sesión correcto:
Cree un archivo denominado cliente o Utils.tsy agregue el siguiente fragmento de código:
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); }
Cree una carpeta denominada usuario en la carpeta src/pages.
Cree un archivo denominado src/pages/user/UserInfo.tsxy agregue el siguiente fragmento de código:
// 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> ); };
Adición de rutas de aplicación
Abra el archivo src/AppRoutes.tsx y reemplace su contenido por el código siguiente:
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>
);
};
Ejecución y prueba de la aplicación
Siga los pasos descritos en Ejecutar y probar la aplicación para ejecutar la aplicación, pero esta vez pruebe el flujo de inicio de sesión con la cuenta de usuario que registró anteriormente.