Partilhar via


Tutorial: Iniciar sessão de utilizadores numa aplicação de página única React utilizando autenticação nativa (pré-visualização)

Aplica-se a: círculo verde com um símbolo de marca de seleção branco que indica que o conteúdo a seguir se aplica a locatários externos. Inquilinos externos (saiba mais)

Neste tutorial, irá autenticar utilizadores num aplicativo de página única (SPA) React usando a autenticação nativa.

Neste tutorial, você:

  • Atualize a aplicação React para permitir que os utilizadores iniciem sessão com e-mail e senha.
  • Teste o fluxo de entrada.

Pré-requisitos

Definir tipos de chamadas que o aplicativo faz para a API de autenticação nativa

Durante o fluxo de entrada, o aplicativo faz várias chamadas para a API de autenticação nativa, como iniciar uma solicitação de entrada, selecionar um método de autenticação e solicitar tokens de segurança.

Para definir essas chamadas, abra o arquivo scr/client/RequestTypes.ts e acrescente o seguinte trecho 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;
    }

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 entrada, abra o arquivo src/client/ResponseTypes.ts e acrescente o seguinte trecho de código:

    export interface TokenResponseType {
        token_type: string;
        scope: string;
        expires_in: number;
        access_token: string;
        refresh_token: string;
        id_token: string;
    }

Processar pedidos de início de sessão

Nesta secção, adiciona código que processa solicitações de fluxo de autenticação. Exemplos dessas solicitações são iniciar um fluxo de entrada, selecionar um método de autenticação ou solicitar um token de segurança.

Para fazer isso, crie um arquivo chamado src/client/SignInService.tse, em seguida, adicione o seguinte trecho 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);
    };

A propriedade challenge_type mostra os métodos de autenticação suportados pelo aplicativo cliente. Este aplicativo entra usando e-mail com senha, então o valor do tipo de desafio é redirecionamento de senha oob. Leia mais sobre tipos de desafio.

Criar componentes da interface do usuário

Durante o fluxo de início de sessão, esta aplicação recolhe as credenciais do utilizador, o endereço de e-mail e a palavra-passe, para autenticar o utilizador. Depois que o usuário entra com êxito, o aplicativo exibe os detalhes do usuário.

  1. Crie uma pasta chamada /pages/signin na pasta src.

  2. Para criar, exibir e enviar o formulário de entrada, crie um arquivo src/pages/signin/SignIn.tsxe, em seguida, adicione o seguinte código:

        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>
          );
        };
    
  3. Para exibir os detalhes do usuário após uma entrada bem-sucedida:

    1. Crie um arquivo chamado client/Utils.tse, em seguida, adicione o seguinte trecho 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);
          }
      
    2. Crie uma pasta chamada usuário na pasta src/pages.

    3. Crie um arquivo chamado src/pages/user/UserInfo.tsxe, em seguida, adicione o seguinte trecho 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>
        );
      };
      

Adicionar rotas de aplicativos

Abra o arquivo src/AppRoutes.tsx e substitua seu conteúdo pelo seguinte código:

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>
  );
};

Executar e testar seu aplicativo

Use as etapas em Executar e testar a sua aplicação para executar a sua aplicação, mas, desta vez, teste o fluxo de início de sessão usando a conta de utilizador que criou anteriormente.

Ativar início de sessão com um alias ou nome de utilizador

Pode permitir que os utilizadores que iniciam sessão com um endereço de e-mail e palavra-passe também iniciem sessão com um nome de utilizador e palavra-passe. O nome de utilizador, também chamado de identificador alternativo de entrada, pode ser um ID de cliente, número de conta ou outro identificador que escolha usar como nome de utilizador.

Pode atribuir nomes de utilizador manualmente à conta de utilizador através do centro de administração do Microsoft Entra ou automatizá-lo na sua aplicação através da API Microsoft Graph.

Siga os passos em Iniciar sessão com um alias ou nome de utilizador para permitir que os seus utilizadores iniciem sessão usando um nome de utilizador na sua aplicação:

  1. Ativar o nome de utilizador no início de sessão.
  2. Crie utilizadores com nome de utilizador no centro de administração ou atualize utilizadores existentes adicionando um nome de utilizador. Alternativamente, pode também automatizar a criação e atualização de utilizadores na sua aplicação usando a Microsoft Graph API.

Próximo passo