将 MSAL React 与类组件配合使用

MSAL React 支持函数组件和类组件。 本文提供有关将 MSAL React 与类组件配合使用的指导,使你能够在类组件中初始化、保护和访问 MSAL React 上下文。

需要注意的是,你无法在类组件内部使用 @azure/msal-react 挂钩。 如果需要访问类组件内的身份验证状态,则需要直接使用 @azure/msal-browser 来获取类似的功能。

先决条件

初始 化

使用 MSAL React 的类组件初始化与函数组件非常相似。 与使用函数组件时类似,你需要在需要访问身份验证状态的组件树顶层放置一个 MsalProvider 组件。

在以下代码片段中,该 MsalProvider 组件用于包装整个应用程序,使 MSAL 实例可供所有子组件使用。 这使子组件能够使用 MSAL 进行用户身份验证、获取令牌和调用受保护的 API。

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

const pca = new PublicClientApplication(config);

class App extends React.Component {
    render() {
        return (
            <MsalProvider instance={pca}>
                <YourAppComponents>
            </ MsalProvider>
        );
    }
}

保护组件

在 MSAL React 中,可以保护组件,然后根据用户的身份验证状态有条件地呈现。 这与使用函数组件的工作方式类似。 主要示例包括:

  • AuthenticatedTemplate - 仅当用户已通过身份验证时,此组件才会渲染其子元素。 如果未对用户进行身份验证,则不会呈现任何内容。
  • UnauthenticatedTemplate - 仅当用户未通过身份验证时,此组件才会渲染其子元素。 如果用户已经过身份验证,则不会呈现任何内容。
  • MsalAuthenticationTemplate - 此组件会先尝试对用户进行身份验证,然后再渲染其子组件。 可以将交互类型(重定向或弹出窗口)指定为属性。如果未对用户进行身份验证,它将启动身份验证过程。

以下代码片段演示如何使用AuthenticatedTemplateUnauthenticatedTemplateMsalAuthenticationTemplate保护 React 组件。 请注意 MSAL Provider 是如何包裹子组件的。

import React from "react";
import { MsalProvider, AuthenticatedTemplate, UnauthenticatedTemplate, MsalAuthenticationTemplate } from "@azure/msal-react";
import { PublicClientApplication, InteractionType } from "@azure/msal-browser";

const pca = new PublicClientApplication(config);

class App extends React.Component {
    render() {
        return (
            <MsalProvider instance={pca}>
                <AuthenticatedTemplate>
                    <span>This will only render for authenticated users</span>
                </ AuthenticatedTemplate>
                <UnauthenticatedTemplate>
                    <span>This will only render for unauthenticated users</span>
                </ UnauthenticatedTemplate>
                <MsalAuthenticationTemplate interactionType={InteractionType.Popup}>
                    <span>This will only render for authenticated users.</span>
                </ MsalAuthenticationTemplate>
            </ MsalProvider>
        );
    }
}

在类组件中获取 MSAL React 上下文

useMsal挂钩不能用于访问类组件中的 MSAL React 上下文。 这是因为 Hook 只能在函数组件中使用,而在函数组件中,你可以在没有实例的情况下使用这些功能。 由于类组件具有实例,因此有 2 个其他选项。 你既可以直接使用原始上下文,也可以使用 withMsal 高阶组件将上下文注入到组件的 props 中。

访问原始上下文

以下代码片段演示如何使用该 MsalContext 代码片段访问类组件中的原始上下文。

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

const pca = new PublicClientApplication(config);

class App extends React.Component {
    render() {
        return (
            <MsalProvider instance={pca}>
                <YourClassComponent/>
            </ MsalProvider>
        );
    }
}

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

    render() {
        const isAuthenticated = this.context.accounts.length > 0;
        if (isAuthenticated) {
            return <span>There are currently {this.context.accounts.length} users signed in!</span>
        }
    }
}

有关工作示例,请参阅 react-router-sample 中的 ProfileRawContext.jsx

通过 withMsal 高阶组件 (HOC) 访问

另一种方法是使用 withMsal 高阶组件,将上下文注入到组件的 props 中。 以下代码片段演示如何使用 withMsal HOC 访问类组件中的 MSAL React 上下文。

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

const pca = new PublicClientApplication(config);

class YourClassComponent extends React.Component {
    render() {
        const isAuthenticated = this.props.msalContext.accounts.length > 0;
        if (isAuthenticated) {
            return <span>There are currently {this.props.msalContext.accounts.length} users signed in!</span>
        }
    }
}

const YourWrappedComponent = withMsal(YourClassComponent);

class App extends React.Component {
    render() {
        return (
            <MsalProvider instance={pca}>
                <YourWrappedComponent />
            </ MsalProvider>
        );
    }
}

有关工作示例,请参阅 react-router-sample 中的 ProfileWithMsal.jsx

使用类组件进行登录

无论采用哪种方法来获取 MSAL React 上下文,使用情况都将相同。 获得上下文对象后,可以调用任何 APIPublicClientApplication,检查登录的帐户,或确定身份验证当前是否正在进行。

以下示例演示如何使用 withMsal HOC 方法登录,但如果需要,可以快速适应其他方法。

注释

请务必记住,对于任何使用上下文的组件,都必须在其上层某一级渲染一个 MsalProvider 组件。 以下示例假设存在提供程序,因此不会演示这一点。

单击按钮后登录

以下代码片段定义使用LoginButton高阶组件的 React 类组件withMsal。 它呈现一个按钮,该按钮在用户未进行身份验证时触发登录弹出窗口,或者注销用户(如果已经过身份验证)。

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

在页面加载时登录

以下代码片段定义使用ProtectedComponent高阶组件的 React 类组件withMsal。 它尝试在装载和更新时对用户进行身份验证,并显示用户是否已进行身份验证,或者是否正在加载页面上进行身份验证。

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

class ProtectedComponent extends React.Component {
    callLogin() {
        const isAuthenticated = this.props.msalContext.accounts.length > 0;
        const msalInstance = this.props.msalContext.instance;

        // If a user is not logged in and authentication is not already in progress, invoke login
        if (!isAuthenticated && this.props.msalContext.inProgress === InteractionStatus.None) {
            msalInstance.loginPopup();
        }
    }
    componentDidMount() {
        this.callLogin();
    }

    componentDidUpdate() {
        this.callLogin();
    }
    
    render() {
        const isAuthenticated = this.props.msalContext.accounts.length > 0;
        if (isAuthenticated) {
            return <span>User is authenticated</span>
        } else {
            return <span>Authentication in progress</span>;
        }
    }
}

export default YourWrappedComponent = withMsal(ProtectedComponent);

另见