Bien démarrer avec MSAL React

Cet article vous guidera tout au long de la procédure de prise en main @azure/msal-react. Nous allons aborder l’initialisation, déterminer si un utilisateur est authentifié, protéger des composants, signer un utilisateur et acquérir un jeton d’accès.

Prerequisites

Initialisation

@azure/msal-react repose sur l’API de contexte React et toutes les parties de votre application qui nécessitent l’authentification doivent être encapsulées dans le MsalProvider composant. Vous devrez d’abord initialiser une instance de PublicClientApplication, puis la passer à MsalProvider comme propriété.

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

Tous les composants sous-jacents MsalProvider auront accès à l’instance PublicClientApplication via le contexte, ainsi que tous les hooks et composants fournis par @azure/msal-react.

Détermination de l’authentification d’un utilisateur

La plupart des applications devront afficher conditionnellement certains composants en fonction de la connexion ou non d’un utilisateur. @azure/msal-react offre 2 façons simples de le faire.

AuthenticatedTemplate et UnauthenticatedTemplate

Les composants AuthenticatedTemplate et UnauthenticatedTemplate affichent leurs composants enfants uniquement si un utilisateur est respectivement authentifié ou non authentifié.

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 crochet

En guise d’alternative aux composants wrapper au-dessus de votre application, vous pouvez utiliser le useIsAuthenticated hook. Vous pouvez en savoir plus sur cela dans Hooks dans 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>
    );
}

Protection des composants

Si vous avez des composants que vous souhaitez uniquement afficher aux utilisateurs authentifiés, vous pouvez utiliser l’une des méthodes ci-dessus. Mais que se passe-t-il si vous souhaitez appeler automatiquement une connexion si un utilisateur n’est pas encore authentifié ? @azure/msal-react propose deux façons de procéder avec le MsalAuthenticationTemplate ou le hook useMsalAuthentication.

MsalAuthenticationTemplate composant

Le composant MsalAuthenticationTemplate affiche ses composants enfants si un utilisateur est authentifié ou tente de connecter un utilisateur. Fournissez-le simplement avec le type d’interaction que vous souhaitez utiliser (redirection ou fenêtre contextuelle) et éventuellement un objet de demande à transmettre à l’API de connexion, un composant à afficher pendant que l’authentification est en cours ou un composant à afficher si une erreur se produit.

Vous trouverez un exemple de travail dans l’un de nos exemples sur la /profile page.

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 crochet

Le useMsalAuthentication hook vérifie d’abord si un utilisateur est connecté, puis tente de connecter un utilisateur s’il n’y a aucun utilisateur connecté. Vous devez fournir le type d’interaction que vous souhaitez utiliser (redirection ou fenêtre contextuelle). Elle retourne le résultat de l’opération de connexion, toute erreur qui s’est produite et la fonction de connexion que vous pouvez utiliser si vous devez réessayer.

Vous pouvez en savoir plus sur ce hook dans la documentation des 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>
    );
}

Connecter un utilisateur à l’aide des API de connexion fournies par @azure/msal-browser

Une autre façon de déclencher une connexion consiste à utiliser directement les API @azure/msal-browser depuis l’instance PublicClientApplication du contexte. Il existe trois façons d’accéder à l’instance à partir du contexte.

useMsal crochet

Un hook qui retourne l’instance PublicClientApplication , un tableau de tous les comptes actuellement connectés et une inProgress valeur qui vous indique ce que msal fait actuellement.

Vous pouvez en savoir plus sur ce hook dans la documentation des 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>
            </>
        );
    }
}

Consommation du contexte brut

Si vous utilisez un composant de classe et que vous ne pouvez pas utiliser de hooks, vous pouvez consommer le contexte msal brut via MsalContext. Vous pouvez en savoir plus sur l’utilisation @azure/msal-react dans les composants de classe ici.

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

Encapsuler votre composant avec le withMsal composant d’ordre supérieur

Une autre façon d'utiliser le contexte MSAL dans les composants de classe et de fonction consiste à encapsuler votre composant avec le HOC withMsal, qui injectera le contexte dans les propriétés de votre composant.

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

Acquisition d’un jeton d’accès

Nous vous recommandons d’appeler l’API acquireTokenSilent sur votre PublicClientApplication objet chaque fois que vous avez besoin d’un jeton d’accès pour accéder à une API. Cela peut être fait de la même façon que les méthodes décrites dans la section précédente.

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

Acquisition d’un jeton d’accès en dehors d’un composant React

Si vous avez besoin d’un jeton d’accès en dehors d’un composant React, vous pouvez appeler directement la acquireTokenSilent fonction sur le PublicClientApplication. Nous vous déconseillons d’appeler des fonctions qui modifient l’état authentifié de l’utilisateur (connexion, déconnexion) en dehors du contexte react fourni par MsalProvider les composants à l’intérieur du contexte peuvent ne pas être correctement mis à jour.

N’oubliez pas que l’utilisateur doit être connecté avant de pouvoir acquérir un jeton.

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

Voir aussi