将 PowerBI 与 React App 集成:crypto_nonexistent 错误

问题描述 投票:0回答:1

我正在尝试将 PowerBI 报告嵌入到 React 应用程序中。我遵循了微软的这个例子。该示例位于

Typescript
但我正在使用
Javascript

这是我的

index.js
文件。

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
import { AuthProvider } from "./context/AuthProvider";
import { CountryProvider } from "./context/CountryProvider";
import theme from "./theme";
import { ThemeProvider } from "@mui/material/styles";
import { Provider } from "react-redux";
import { store } from "./store/store";
import * as config from "./pages/powerbi/keys";
import { LogLevel, PublicClientApplication } from "@azure/msal-browser";
import { MsalProvider } from "@azure/msal-react";

// TRIED THIS TO FIX THE ISSUE
if (typeof window !== 'undefined' && !window.crypto) {
  window.crypto = window.msCrypto;
}

const msalInstance = new PublicClientApplication({
  auth: {
      clientId: config.clientId,
      authority: config.authorityUrl,
      redirectUri: "http://{SERVER_IP_ADDRESS}/FOLDER_NAME/"
  },
  cache: {
      cacheLocation: 'localStorage', 
      storeAuthStateInCookie: false,
  },
  system: {
    loggerOptions: {
      loggerCallback: (level, message, containsPii) => {
        console.log(`LEVEL: ${level} MESSAGE: ${message}`);
      },
      piiLoggingEnabled: false,
      logLevel: LogLevel.Verbose
    },
    cryptoOptions: {
      usePkce: false // TRIED THIS TO FIX THE ISSUE
    }
  }
});

console.log("CRYPTO: ", window.crypto);

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
   <div id="MainDiv">
      <Provider store={store}>
         <BrowserRouter basename="Reactjs_Demo/">
            <AuthProvider>
               <CountryProvider>
                  <ThemeProvider theme={theme}>
                     <MsalProvider instance={msalInstance}>
                     <App />
                     </MsalProvider>
                  </ThemeProvider>
               </CountryProvider>
            </AuthProvider>
         </BrowserRouter>
      </Provider>
   </div>
);

这是

PowerBI
组件

import React, { useEffect, useRef, useState, useContext } from "react";
import { AuthenticationResult, InteractionType, EventType, AuthError } from "@azure/msal-browser";
import { MsalContext } from "@azure/msal-react";
import { service, factories, models } from "powerbi-client";
import * as config from "./keys";

const powerbi = new service.Service(factories.hpmFactory, factories.wpmpFactory, factories.routerFactory);

export default function PowerBiReport() {
    const [accessToken, setAccessToken] = useState("");
    const [embedUrl, setEmbedUrl] = useState("");
    const [error, setError] = useState([]);
    const reportRef = useRef(null);
    const context = useContext(MsalContext);

    const authenticate = () => {
        const msalInstance = context.instance;
        const msalAccounts = context.accounts;
        const msalInProgress = context.inProgress;
        const isAuthenticated = context.accounts.length > 0;

        if (error.length > 0) {
            return;
        }

        const eventCallback = msalInstance.addEventCallback((message) => {
            if (message.eventType === EventType.LOGIN_SUCCESS && !accessToken) {
                const payload = message.payload;
                const name = payload.account?.name ? payload.account?.name : "";
                setAccessToken(payload.accessToken);
                setUsername(name);
                tryRefreshUserPermissions();
            }
        });

        const loginRequest = { scopes: config.scopeBase, account: msalAccounts[0] };

        if (!isAuthenticated && msalInProgress === InteractionType.None) {
            msalInstance.loginRedirect(loginRequest);
        } else if (isAuthenticated && accessToken && !embedUrl) {
            getEmbedUrl();
            msalInstance.removeEventCallback(eventCallback);
        } else if (isAuthenticated && !accessToken && !embedUrl && msalInProgress === InteractionType.None) {
            setUsername(msalAccounts[0].name);
            msalInstance.acquireTokenSilent(loginRequest).then((response) => {
                setAccessToken(response.accessToken);
                getEmbedUrl();
            }).catch((error) => {
                if (error.errorCode === "consent_required" || error.errorCode === "interaction_required" || error.errorCode === "login_required") {
                    msalInstance.acquireTokenRedirect(loginRequest);
                } else if (error.errorCode === '429') {
                    setError(["Our Service Token Server (STS) is overloaded, please try again in sometime"]);
                } else {
                    setError(["There was some problem fetching the access token" + error.toString()]);
                }
            });
        }
    };

    const tryRefreshUserPermissions = () => {
        fetch(config.powerBiApiUrl + "v1.0/myorg/RefreshUserPermissions", {
            headers: { "Authorization": "Bearer " + accessToken },
            method: "POST"
        })
        .then(response => {
            if (response.ok) {
                console.log("User permissions refreshed successfully.");
            } else {
                if (response.status === 429) {
                    console.error("Permissions refresh will be available in up to an hour.");
                } else {
                    console.error(response);
                }
            }
        })
        .catch(error => {
            console.error("Failure in making API call." + error);
        });
    };

    const getEmbedUrl = () => {
        fetch(config.powerBiApiUrl + "v1.0/myorg/groups/" + config.wspaceId + "/reports/" + config.reportId, {
            headers: { "Authorization": "Bearer " + accessToken },
            method: "GET"
        })
        .then(response => {
            const errorMessage = ["Error occurred while fetching the embed URL of the report", "Request Id: " + response.headers.get("requestId")];
            response.json()
            .then(body => {
                if (response.ok) {
                    setEmbedUrl(body["embedUrl"]);
                } else {
                    errorMessage.push("Error " + response.status + ": " + body.error.code);
                    setError(errorMessage);
                }
            })
            .catch(() => {
                errorMessage.push("Error " + response.status + ": An error has occurred");
                setError(errorMessage);
            });
        })
        .catch(error => {
            setError([error]);
        });
    };

    const setUsername = (username) => {
        const welcome = document.getElementById("welcome");
        if (welcome !== null) welcome.innerText = "Welcome, " + username;
    };

    useEffect(() => {
        if (reportRef.current !== null) {
            const reportContainer = reportRef.current;
            if (error.length) {
                reportContainer.textContent = "";
                error.forEach(line => {
                    reportContainer.appendChild(document.createTextNode(line));
                    reportContainer.appendChild(document.createElement("br"));
                });
            } else if (accessToken !== "" && embedUrl !== "") {
                const embedConfiguration = {
                    type: "report",
                    tokenType: models.TokenType.Aad,
                    accessToken,
                    embedUrl,
                    id: config.reportId,
                };
                const report = powerbi.embed(reportContainer, embedConfiguration);
                report.off("loaded");
                report.on("loaded", () => {
                    console.log("Report load successful");
                });
                report.off("rendered");
                report.on("rendered", () => {
                    console.log("Report render successful");
                });
                report.off("error");
                report.on("error", (event) => {
                    const errorMsg = event.detail;
                    console.error(errorMsg);
                });
            }
        }
    }, [accessToken, embedUrl, error]);

    useEffect(() => {
        authenticate();
    }, []);

    useEffect(() => {
        return () => {
            if (reportRef.current) {
                powerbi.reset(reportRef.current);
            }
        };
    }, []);

    return (
        <div>
            <div id="welcome"></div>
            <div ref={reportRef}>
                Loading the report...
            </div>
        </div>
    );
};


当我在端口 3000 上本地运行该项目时,我没有收到任何错误。但是当我部署到服务器时,我收到以下错误

Uncaught BrowserAuthError: crypto_nonexistent: The crypto object or function is not available.

该项目是使用

CRA
创建的。怎么解决这个问题?

javascript reactjs azure powerbi-embedded msal-react
1个回答
0
投票

Windows Server 上的 IIS 上托管的 React 应用程序启用 HTTPS。您需要 SSL 证书才能启用 HTTPS。

创建用于内部测试的自签名证书。使用 IIS 管理器创建或导入证书。

打开

IIS Manager

enter image description here

  • 双击服务器证书

  • 在操作面板中,单击创建自签名证书

enter image description here

为其命名(例如,

MyTestCert
),它将出现在列表中。

enter image description here

创建 SSL 证书后 将证书绑定到站点

  • 导航到“站点”节点下的应用程序/站点。

enter image description here

  • 在右侧面板中,单击“绑定”。

  • 添加 https 绑定并选择您的 SSL 证书。

enter image description here

选择

HTTPS

enter image description here

enter image description here

MSAL 身份验证建议使用 HTTPS,特别是对于生产应用程序。 MSAL 尝试使用

crypto
API 执行身份验证任务(例如生成令牌)。您可以使用自定义加密选项配置 MSAL,以防止在
crypto
不可用时出现错误。

© www.soinside.com 2019 - 2024. All rights reserved.