Kom igång med MSAL React

Den här artikeln beskriver hur du kommer igång med @azure/msal-react. Vi tar upp initiering, avgör om en användare autentiseras, skyddar komponenter, loggar in en användare och hämtar en åtkomsttoken.

Förutsättningar

Initialisering

@azure/msal-react bygger på React-kontext-API: et och alla delar av din app som kräver autentisering måste omslutas i komponenten MsalProvider . Du måste först initiera en instans av PublicClientApplication och sedan skicka den till MsalProvider som en 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 />);

Alla komponenter under MsalProvider har åtkomst till PublicClientApplication-instansen via kontext samt alla krokar och komponenter som tillhandahålls av @azure/msal-react.

Avgöra om en användare autentiseras

De flesta program måste villkorligt återge vissa komponenter baserat på om en användare är inloggad eller inte. @azure/msal-react tillhandahåller två enkla sätt att göra detta på.

AuthenticatedTemplate och UnauthenticatedTemplate

AuthenticatedTemplate- och UnauthenticatedTemplate-komponenterna renderar bara sitt innehåll om en användare är autentiserad respektive inte är autentiserad.

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 hook

Som ett alternativ till wrapperkomponenterna ovan kan din app använda hooken useIsAuthenticated. Du kan läsa mer om detta i Hooks i 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>
    );
}

Skydda komponenter

Om du har komponenter som du bara vill visa för autentiserade användare kan du använda någon av metoderna ovan. Men vad händer om du vill anropa en inloggning automatiskt om en användare ännu inte har autentiserats? @azure/msal-react erbjuder två sätt att göra detta med MsalAuthenticationTemplate eller hooken useMsalAuthentication.

MsalAuthenticationTemplate komponent

Komponenten MsalAuthenticationTemplate renderar sitt innehåll om en användare är autentiserad eller försöker logga in en användare. Ange bara den interaktionstyp som du vill använda (omdirigering eller popup-fönster) och om du vill skicka ett begärandeobjekt till inloggnings-API:et, en komponent som ska visas medan autentisering pågår eller en komponent som ska visas om ett fel inträffar.

Du hittar ett fungerande exempel på detta i något av våra exempel på sidan /profile .

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 hook

Kroken useMsalAuthentication kontrollerar först om en användare är inloggad och försöker sedan logga in en användare om det inte finns några inloggade användare. Du måste ange den interaktionstyp som du vill använda (omdirigering eller popup-fönster). Det returnerar resultatet av inloggningsåtgärden, eventuella fel som uppstod och den inloggningsfunktion som du kan använda om du behöver försöka igen.

Du kan läsa mer om den här hooken i dokumentationen om 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>
    );
}

Logga in en användare med hjälp av inloggnings-API:er som tillhandahålls av @azure/msal-browser

Ett annat sätt att initiera en inloggning är att använda @azure/msal-browser API:er direkt från PublicClientApplication-instansen i kontexten. Det finns tre sätt att komma åt instansen från kontexten.

useMsal hook

En krok som returnerar instansen PublicClientApplication , en matris med alla konton som för närvarande är inloggade och ett inProgress värde som anger vad msal gör för närvarande.

Du kan läsa mer om den här hooken i hooks-dokumentationen.

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

Använda råkontexten

Om du använder en klasskomponent och inte kan använda hooks kan du få åtkomst till den underliggande MSAL-kontexten via MsalContext. Du kan läsa mer om hur du använder @azure/msal-react i klasskomponenter här.

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

Omslut komponenten med Higher-Order-Component withMsal

Ett annat sätt att använda MSAL-kontexten i både klass- och funktionskomponenter är att omsluta din komponent med HOC:n withMsal, som injicerar kontexten i komponentens props.

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

Hämta en åtkomsttoken

Vi rekommenderar att din app anropar API:et acquireTokenSilent på objektet PublicClientApplication varje gång du behöver en åtkomsttoken för att få åtkomst till ett API. Detta kan göras på liknande sätt som i föregående avsnitt.

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

Hämta en åtkomsttoken utanför en React-komponent

Om du behöver en åtkomsttoken utanför en React-komponent kan du anropa acquireTokenSilent funktionen direkt på PublicClientApplication. Vi rekommenderar inte att du anropar funktioner som ändrar användarens autentiserade tillstånd (inloggning, utloggning) utanför react-kontexten som tillhandahålls av MsalProvider eftersom komponenterna i kontexten kanske inte uppdateras korrekt.

Tänk på att användaren måste vara inloggad innan du kan hämta en 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
};

Se även