Comece com o MSAL React

Este artigo vai guiá-lo por como começar com @azure/msal-react. Vamos abordar a inicialização, a determinação se um utilizador está autenticado, a proteção dos componentes, o início de sessão do utilizador e a aquisição de um token de acesso.

Pré-requisitos

Inicialização

@azure/msal-react é construída sobre a API de contexto do React e todas as partes da sua aplicação que requerem autenticação devem estar integradas no MsalProvider componente. Primeiro terás de inicializar uma instância de PublicClientApplication e depois passar isso como MsalProvider prop.

import React from "react";
import { createRoot } from "react-dom/client";

import { MsalProvider } from "@azure/msal-react";
import { Configuration,  PublicClientApplication } from "@azure/msal-browser";

import App from "./app.jsx";

// MSAL configuration
const configuration: Configuration = {
    auth: {
        clientId: "client-id"
    }
};

const pca = new PublicClientApplication(configuration);

// Component
const AppProvider = () => (
    <MsalProvider instance={pca}>
        <App />
    </MsalProvider>
);

const root = createRoot(document.getElementById("root"));
root.render(<AppProvider />);

Todos os componentes abaixo de MsalProvider terão acesso à instância PublicClientApplication através do contexto, assim como todos os hooks e componentes fornecidos por @azure/msal-react.

Determinar se um utilizador está autenticado

A maioria das aplicações terá de renderizar condicionalmente certos componentes consoante o utilizador tenha ou não sessão iniciada. @azure/msal-react Fornece 2 formas simples de fazer isto.

AuthenticatedTemplate e UnauthenticatedTemplate

AuthenticatedTemplate e UnauthenticatedTemplate os componentes só renderizam os seus filhos se um utilizador estiver autenticado ou não autenticado, respetivamente.

import React from 'react';
import { AuthenticatedTemplate, UnauthenticatedTemplate } from "@azure/msal-react";

export function App() {
    return (
        <React.Fragment>
            <p>Anyone can see this paragraph.</p>
            <AuthenticatedTemplate>
                <p>At least one account is signed in!</p>
            </AuthenticatedTemplate>
            <UnauthenticatedTemplate>
                <p>No users are signed in!</p>
            </UnauthenticatedTemplate>
        </React.Fragment>
    );
}

useIsAuthenticated gancho

Como alternativa aos componentes do wrapper acima, a sua aplicação pode usar o useIsAuthenticated gancho. Pode ler mais sobre isto em Hooks no MSAL React.

import React from 'react';
import { useIsAuthenticated } from "@azure/msal-react";

export function App() {
    const isAuthenticated = useIsAuthenticated();

    return (
        <React.Fragment>
            <p>Anyone can see this paragraph.</p>
            {isAuthenticated && (
                <p>At least one account is signed in!</p>
            )}
            {!isAuthenticated && (
                <p>No users are signed in!</p>
            )}
        </React.Fragment>
    );
}

Componentes de Proteção

Se tens componentes que só queres mostrar a utilizadores autenticados, podes usar qualquer um dos métodos acima. Mas e se quiser invocar automaticamente um login se um utilizador ainda não estiver autenticado? @azure/msal-react fornece duas formas de o fazer com o hook MsalAuthenticationTemplate ou com o hook useMsalAuthentication.

MsalAuthenticationTemplate componente

O MsalAuthenticationTemplate componente irá renderizar os seus filhos se um utilizador for autenticado ou tentar iniciar sessão com um utilizador. Basta fornecer-lhe o tipo de interação que pretende usar (redirecionar ou popup) e, opcionalmente, um objeto de pedido para ser passado à API de login, um componente para mostrar enquanto a autenticação está em curso ou um componente para mostrar caso ocorra um erro.

Pode encontrar um exemplo funcional disto em qualquer um dos nossos exemplos na /profile página.

import React from "react";
import { MsalAuthenticationTemplate } from "@azure/msal-react";
import { InteractionType } from "@azure/msal-browser";

function ErrorComponent({error}) {
    return <p>An Error Occurred: {error}</p>;
}

function LoadingComponent() {
    return <p>Authentication in progress...</p>;
}

export function Example() {
    const authRequest = {
        scopes: ["openid", "profile"]
    };

    return (
        // authenticationRequest, errorComponent and loadingComponent props are optional
        <MsalAuthenticationTemplate 
            interactionType={InteractionType.Popup} 
            authenticationRequest={authRequest} 
            errorComponent={ErrorComponent} 
            loadingComponent={LoadingComponent}
        >
            <p>At least one account is signed in!</p>
        </MsalAuthenticationTemplate>
      )
};

useMsalAuthentication gancho

O hook useMsalAuthentication verifica primeiro se um utilizador tem sessão iniciada e, em seguida, tenta iniciar a sessão de um utilizador se não houver utilizadores com sessão iniciada. Terá de fornecer o tipo de interação que gostaria de usar (redirecionar ou pop-up). Vai devolver o resultado da operação de login, qualquer erro que tenha ocorrido e a função de login que pode usar se precisar de tentar novamente.

Pode ler mais sobre este hook na documentação sobre hooks.

import React from 'react';
import { useMsalAuthentication } from "@azure/msal-react";
import { InteractionType } from '@azure/msal-browser';

export function App() {
    const {login, result, error} = useMsalAuthentication(InteractionType.Popup);

    return (
        <React.Fragment>
            <p>Anyone can see this paragraph.</p>
            <AuthenticatedTemplate>
                <p>At least one account is signed in!</p>
            </AuthenticatedTemplate>
            <UnauthenticatedTemplate>
                <p>No users are signed in!</p>
            </UnauthenticatedTemplate>
        </React.Fragment>
    );
}

Iniciar sessão de um utilizador usando as APIs de login fornecidas por @azure/msal-browser

Outra forma de invocar um início de sessão é utilizando diretamente as APIs @azure/msal-browser a partir da instância PublicClientApplication no contexto. Existem 3 formas de aceder à instância a partir do contexto.

useMsal gancho

Um hook que devolve a instância PublicClientApplication, um array com todas as contas com sessão iniciada atualmente e um valor inProgress que indica o que o MSAL está atualmente a fazer.

Pode ler mais sobre este hook na documentação sobre hooks.

import React from 'react';
import { useMsal } from "@azure/msal-react";

export function App() {
    const { instance, accounts, inProgress } = useMsal();

    if (accounts.length > 0) {
        return <span>There are currently {accounts.length} users signed in!</span>
    } else if (inProgress === "login") {
        return <span>Login is currently in progress!</span>
    } else {
        return (
            <>
                <span>There are currently no users signed in!</span>
                <button onClick={() => instance.loginPopup()}>Login</button>
            </>
        );
    }
}

Utilizar o contexto bruto

Se estiveres a usar um componente de classe e não puderes usar hooks, podes consumir o contexto MSAL em bruto através de MsalContext. Pode ler mais sobre como usar @azure/msal-react em componentes de classe aqui.

import React from "react";
import { MsalContext } from "@azure/msal-react";

class App extends React.Component {
    static contextType = MsalContext;

    render() {
        if (this.context.accounts.length > 0) {
            return <span>There are currently {this.context.accounts.length} users signed in!</span>
        } else if (this.context.inProgress === "login") {
            return <span>Login is currently in progress!</span>
        } else {
            return (
                <>
                    <span>There are currently no users signed in!</span>
                    <button onClick={() => this.context.instance.loginPopup()}>Login</button>
                </>
            );
        }
    }
}

Encapsular o seu componente com o withMsal componente de ordem superior

Outra forma de consumir o contexto MSAL tanto em componentes em classe como em componentes funcionais é envolver o seu componente com o HOC withMsal, que injeta o contexto nas propriedades do seu componente.

import React from "react";
import { withMsal } from "@azure/msal-react";

class LoginButton extends React.Component {
    render() {
        const isAuthenticated = this.props.msalContext.accounts.length > 0;
        const msalInstance = this.props.msalContext.instance;
        if (isAuthenticated) {
            return <button onClick={() => msalInstance.logout()}>Logout</button>    
        } else {
            return <button onClick={() => msalInstance.loginPopup()}>Login</button>
        }
    }
}

export default YourWrappedComponent = withMsal(LoginButton);

Aquisição de um token de acesso

Recomendamos que a sua aplicação chame a acquireTokenSilent API do seu PublicClientApplication objeto sempre que precisar de um token de acesso para aceder a uma API. Isto pode ser feito de forma semelhante às formas descritas na secção anterior.

import React, { useState, useEffect } from "react"
import { useMsal, useAccount } from "@azure/msal-react";

export function App() {
    const { instance, accounts, inProgress } = useMsal();
    const account = useAccount(accounts[0] || {});
    const [apiData, setApiData] = useState(null);

    useEffect(() => {
        if (account) {
            instance.acquireTokenSilent({
                scopes: ["User.Read"],
                account: account
            }).then((response) => {
                if(response) {
                    callMsGraph(response.accessToken).then((result) => setApiData(result));
                }
            });
        }
    }, [account, instance]);

    if (accounts.length > 0) {
        return (
            <>
                <span>There are currently {accounts.length} users signed in!</span>
                {apiData && (<span>Data retreived from API: {JSON.stringify(apiData)}</span>)}
            </>
        );
    } else if (inProgress === "login") {
        return <span>Login is currently in progress!</span>
    } else {
        return <span>There are currently no users signed in!</span>
    }
}

Aquisição de um token de acesso fora de um componente React

Se precisar de um token de acesso fora de um componente React, pode chamar diretamente a acquireTokenSilent função no PublicClientApplication. Não recomendamos chamar funções que alterem o estado autenticado do utilizador (login, logout) fora do contexto react fornecido por por MsalProvider , pois os componentes dentro do contexto podem não ser atualizados corretamente.

Tenha em mente que o utilizador tem de ter iniciado sessão antes de poder obter um token.

import { PublicClientApplication } from "@azure/msal-browser";

// This should be the same instance you pass to MsalProvider
const msalInstance = new PublicClientApplication(config);

const acquireAccessToken = async (msalInstance) => {
    const activeAccount = msalInstance.getActiveAccount(); // This will only return a non-null value if you have logic somewhere else that calls the setActiveAccount API
    const accounts = msalInstance.getAllAccounts();

    if (!activeAccount && accounts.length === 0) {
        /*
        * User is not signed in. Throw error or wait for user to login.
        * Do not attempt to log a user in outside of the context of MsalProvider
        */   
    }
    const request = {
        scopes: ["User.Read"],
        account: activeAccount || accounts[0]
    };

    const authResult = await msalInstance.acquireTokenSilent(request);

    return authResult.accessToken
};

Consulte também