Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Aplica-se a:
Locatários externos (saiba mais)
Neste tutorial, você aprenderá a redefinir a senha em um SPA (aplicativo de página única) do React usando a autenticação nativa.
Neste tutorial, você:
- Atualize o aplicativo React para redefinir a senha do usuário.
- Testar o fluxo de redefinição de senha
Pré-requisitos
- Conclua as etapas no Tutorial: Configure o servidor proxy CORS para gerenciar cabeçalhos CORS para autenticação nativa.
Definir tipos de chamadas que o aplicativo faz para a API de autenticação nativa
Durante o fluxo de redefinição de senha, o aplicativo faz várias chamadas para a API de autenticação nativa, como iniciar uma solicitação de redefinição de senha e enviar um formulário de redefinição de senha.
Para definir essas chamadas, abra o arquivo scr/client/RequestTypes.ts e acrescente o seguinte snippet de código:
export interface ResetPasswordStartRequest {
username: string;
challenge_type: string;
client_id: string;
}
export interface ResetPasswordSubmitRequest {
client_id: string;
continuation_token: string;
new_password: string;
}
export interface ResetPasswordSubmitForm {
continuation_token: string;
new_password: string;
}
Definir o tipo de resposta 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 redefinição de senha, abra o arquivo src/client/ResponseTypes.ts e acrescente o seguinte snippet de código:
export interface ChallengeResetResponse {
continuation_token: string;
expires_in: number;
}
export interface ResetPasswordSubmitResponse {
continuation_token: string;
poll_interval: number;
}
Processar solicitações de redefinição de senha
Nesta seção, você adicionará um código que processa solicitações de fluxo de redefinição de senha. Exemplos dessas solicitações são iniciar uma solicitação de redefinição de senha e enviar um formulário de redefinição de senha.
Para fazer isso, crie um arquivo chamado src/client/ResetPasswordService.ts e adicione o seguinte snippet de código:
import { CLIENT_ID, ENV } from "../config";
import { postRequest } from "./RequestClient";
import { ChallengeForm, ChallengeRequest, ResetPasswordStartRequest, ResetPasswordSubmitForm, ResetPasswordSubmitRequest } from "./RequestTypes";
import { ChallengeResetResponse, ChallengeResponse, ResetPasswordSubmitResponse } from "./ResponseTypes";
export const resetStart = async ({ username }: { username: string }) => {
const payloadExt: ResetPasswordStartRequest = {
username,
client_id: CLIENT_ID,
challenge_type: "password oob redirect",
};
return await postRequest(ENV.urlResetPwdStart, payloadExt);
};
export const resetChallenge = async ({ continuation_token }: { continuation_token: string }): Promise<ChallengeResponse> => {
const payloadExt: ChallengeRequest = {
continuation_token,
client_id: CLIENT_ID,
challenge_type: "oob redirect",
};
return await postRequest(ENV.urlResetPwdChallenge, payloadExt);
};
export const resetSubmitOTP = async (payload: ChallengeForm): Promise<ChallengeResetResponse> => {
const payloadExt = {
client_id: CLIENT_ID,
continuation_token: payload.continuation_token,
oob: payload.oob,
grant_type: "oob",
};
return await postRequest(ENV.urlResetPwdContinue, payloadExt);
};
export const resetSubmitNewPassword = async (payload: ResetPasswordSubmitForm): Promise<ResetPasswordSubmitResponse> => {
const payloadExt: ResetPasswordSubmitRequest = {
client_id: CLIENT_ID,
continuation_token: payload.continuation_token,
new_password: payload.new_password,
};
return await postRequest(ENV.urlResetPwdSubmit, payloadExt);
};
export const resetPoll = async (continuation_token: string): Promise<ChallengeResetResponse> => {
const payloadExt = {
client_id: CLIENT_ID,
continuation_token,
};
return await postRequest(ENV.urlResetPwdPollComp, payloadExt);
};
A challenge_type propriedade mostra os métodos de autenticação aos quais o aplicativo cliente dá suporte. Leia mais sobre os tipos de desafio.
Criar componentes de interface do usuário
Durante o fluxo de redefinição de senha, esse aplicativo, em telas diferentes, coleta o nome de usuário do usuário (email), uma senha única e uma nova senha de usuário.
Crie uma pasta chamada /pages/resetpassword na pasta src .
Para criar, exibir e enviar os formulários de redefinição de senha, crie um arquivo src/pages/resetpassword/ResetPassword.tsx e adicione o seguinte código:
// ResetPassword.tsx import React, { useState } from "react"; import { resetChallenge, resetStart, resetSubmitNewPassword, resetSubmitOTP } from "../../client/ResetPasswordService"; import { ChallengeResetResponse, ChallengeResponse, ErrorResponseType } from "../../client/ResponseTypes"; export const ResetPassword: React.FC = () => { const [username, setUsername] = useState<string>(""); const [otp, setOTP] = useState<string>(""); const [newPassword, setNewPassword] = useState<string>(""); const [error, setError] = useState<string>(""); const [step, setStep] = useState<number>(1); const [isLoading, setIsloading] = useState<boolean>(false); const [tokenRes, setTokenRes] = useState<ChallengeResponse>({ binding_method: "", challenge_channel: "", challenge_target_label: "", challenge_type: "", code_length: 0, continuation_token: "", interval: 0, }); const [otpRes, setOTPRes] = useState<ChallengeResetResponse>({ expires_in: 0, continuation_token: "", }); const handleResetPassword = async (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); if (!username) { setError("Username is required"); return; } setError(""); try { setIsloading(true); const res1 = await resetStart({ username }); const tokenRes = await resetChallenge({ continuation_token: res1.continuation_token }); setTokenRes(tokenRes); setStep(2); } catch (err) { setError("An error occurred during password reset " + (err as ErrorResponseType).error_description); } finally { setIsloading(false); } }; const handleSubmitCode = async (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); if (!otp) { setError("All fields are required"); return; } setError(""); try { setIsloading(true); const res = await resetSubmitOTP({ continuation_token: tokenRes.continuation_token, oob: otp, }); setOTPRes(res); setStep(3); } catch (err) { setError("An error occurred while submitting the otp code " + (err as ErrorResponseType).error_description); } finally { setIsloading(false); } }; const handleSubmitNewPassword = async (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); if (!newPassword) { setError('All fields are required'); return; } setError(''); try { setIsloading(true); await resetSubmitNewPassword({ continuation_token: otpRes.continuation_token, new_password: newPassword, }); setStep(4); } catch (err) { setError("An error occurred while submitting the new password " + (err as ErrorResponseType).error_description); } finally { setIsloading(false); } }; return ( <div className="reset-password-form"> //collect username to initiate password reset flow {step === 1 && ( <form onSubmit={handleResetPassword}> <h2>Reset Password</h2> <div className="form-group"> <label>Username:</label> <input type="text" value={username} onChange={(e) => setUsername(e.target.value)} required /> </div> {error && <div className="error">{error}</div>} {isLoading && <div className="warning">Sending request...</div>} <button type="submit">Reset Password</button> </form> )} //collect OTP {step === 2 && ( <form onSubmit={handleSubmitCode}> <h2>Submit one time code received via email at {tokenRes.challenge_target_label}</h2> <div className="form-group"> <label>One time code:</label> <input type="text" maxLength={tokenRes.code_length} value={otp} onChange={(e) => setOTP(e.target.value)} required /> </div> {error && <div className="error">{error}</div>} {isLoading && <div className="warning">Sending request...</div>} <button type="submit">Submit code</button> </form> )} //Collect new password {step === 3 && ( <form onSubmit={handleSubmitNewPassword}> <h2>Submit New Password</h2> <div className="form-group"> <label>New Password:</label> <input type="password" value={newPassword} onChange={(e) => setNewPassword(e.target.value)} required /> </div> {error && <div className="error">{error}</div>} {isLoading && <div className="warning">Sending request...</div>} <button type="submit">Submit New Password</button> </form> )} //report success after password reset is successful {step === 4 && ( <div className="reset-password-success"> <h2>Password Reset Successful</h2> <p>Your password has been reset successfully. You can now log in with your new password.</p> </div> )} </div> ); };
Adicionar rotas de aplicativo
Abra o arquivo src/AppRoutes.tsx e descompacte as seguintes linhas de código:
//uncomment
import { ResetPassword } from "./pages/ResetAccount/ResetPassword";
//...
export const AppRoutes = () => {
return (
<Routes>
//uncomment
<Route path="/reset" element={<ResetPassword />} />
</Routes>
);
};
Executar e testar seu aplicativo
Use as etapas em Executar e teste seu aplicativo para executar seu aplicativo. No entanto, teste o fluxo de redefinição de senha apenas usando a conta de usuário que você se inscreveu anteriormente.
Conteúdo relacionado
- Configure um proxy reverso para um aplicativo de página única que usa a API de autenticação nativa usando o Aplicativo de Funções do Azure.
- Use o Azure Front Door como um proxy reverso no ambiente de produção para um aplicativo de página única que usa autenticação nativa.
- Referência da API de autenticação nativa.