Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Aplica-se a:
Inquilinos externos (saiba mais)
Neste tutorial, você aprenderá a criar um aplicativo de página única do React que inscreve usuários usando autenticação nativa.
Neste tutorial, você:
- Crie um projeto React.
- Adicione componentes da interface do usuário do aplicativo.
- Configure o projeto para inscrever o usuário usando nome de usuário (e-mail) e senha.
Pré-requisitos
- Conclua as etapas em Guia de início rápido: entre usuários em um aplicativo de página única React de exemplo usando a API de autenticação nativa. Este guia de início rápido mostra como preparar o seu tenant externo e executar um exemplo prático de código React.
- Visual Studio Code ou outro editor de código.
- Node.js.
Criar um projeto React e instalar dependências
Em um local de escolha em seu computador, execute os seguintes comandos para criar um novo projeto React com o nome reactspa, navegue até a pasta do projeto e instale pacotes:
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
Adicionar arquivo de configuração para seu aplicativo
Crie um arquivo chamado src/config.jse, em seguida, adicione o seguinte código:
// 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`,
}
Encontre o valor
Enter_the_Application_Id_Heree substitua-o pelo Application ID (clientId) do aplicativo que você registrou no centro de administração do Microsoft Entra.O
BASE_API_URLaponta para um servidor proxy CORS (Cross-Origin Resource Sharing), que iremos configurar mais tarde nesta série de tutoriais. A API de autenticação nativa não suporta CORS, por isso configuramos um servidor proxy CORS entre o SPA React e a API de autenticação nativa para gerenciar os cabeçalhos CORS.
Configurar o aplicativo React para chamar a API de autenticação nativa e manipular a resposta
Para concluir um fluxo de autenticação, como um fluxo de inscrição, com as APIs de autenticação nativas, o aplicativo faz com que calla dn manipule a resposta. Por exemplo, o aplicativo inicia um fluxo de inscrição e aguarda uma resposta, em seguida, envia atributos de usuário e aguarda novamente até que o usuário seja inscrito com êxito.
Configurar a chamada do cliente para a API de autenticação nativa
Nesta seção, você define como fazer chamadas para a autenticação nativa e manipular respostas:
Crie uma pasta chamada cliente no src.
Crie um arquivo chamado scr/client/RequestClient.ts e adicione o seguinte trecho de código:
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(); };Esse código define como o aplicativo faz chamadas para a API de autenticação nativa e como lidar com as respostas. Sempre que o aplicativo precisa iniciar um fluxo de autenticação, ele usa a função
postRequestespecificando a URL e os dados de carga.
Definir tipos de chamadas que o aplicativo faz para a API de autenticação nativa
Durante o fluxo de inscrição, o aplicativo faz várias chamadas para a API de autenticação nativa.
Para definir essas chamadas, crie um arquivo chamado scr/client/RequestTypes.ts e adicione o seguinte trecho de código:
//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;
}
Definir o tipo de respostas que o aplicativo recebe da API de autenticação nativa
Para definir o tipo de respostas que o aplicativo pode receber da API de autenticação nativa para a operação de inscrição, crie um arquivo chamado src/client/ResponseTypes.ts e adicione o seguinte trecho de código:
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;
}
Processar os pedidos de inscrição
Nesta seção, você adiciona código que processa solicitações de fluxo de inscrição. Exemplos dessas solicitações são iniciar um fluxo de inscrição, selecionar um método de autenticação e enviar uma senha única.
Para fazer isso, crie um arquivo chamado src/client/SignUpService.ts e adicione o seguinte trecho de código:
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);
};
A propriedade challenge_type mostra os métodos de autenticação suportados pelo aplicativo cliente. Este aplicativo autentica-se utilizando e-mail com senha, por isso o valor do tipo de desafio é redirecionamento de senha oob. Leia mais sobre os tipos de desafios .
Criar componentes da interface do usuário
Este aplicativo coleta detalhes do usuário, como nome próprio, nome de usuário (e-mail) e senha e uma senha única do usuário. Portanto, o aplicativo precisa ter uma inscrição e um formulário único de coleta de senha.
Crie uma pasta chamada /pages/SignUp na pasta src .
Para criar, exibir e enviar o formulário de inscrição, crie um arquivo src/pages/SignUp/SignUp.tsx e adicione o seguinte código:
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> ); };Para criar, exibir e enviar o formulário de senha única, crie um arquivo src/pages/signup/SignUpChallenge.tsx e adicione o seguinte código:
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> ); };Crie um arquivo src/pages/signup/SignUpCompleted.tsx e adicione o seguinte código:
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> ); };Esta página exibe uma mensagem de sucesso e um botão para levar o usuário à página de entrada depois que ele se inscrever com êxito.
Abra o arquivo src/App.tsx e substitua seu conteúdo pelo seguinte código:
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;Para exibir o aplicativo React corretamente:
Abra o arquivo src/App.css e adicione a seguinte propriedade na
App-headerclasse:min-height: 100vh;Abra o ficheiro src/Index.css e, em seguida, substitua o seu conteúdo pelo código de src/index.css
Adicionar rotas de aplicativos
Crie um arquivo chamado src/AppRoutes.tsx e adicione o seguinte código:
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>
);
};
Neste ponto, seu aplicativo React pode enviar solicitações de inscrição para a API de autenticação nativa, mas precisamos configurar o servidor proxy CORS para gerenciar os cabeçalhos CORS.