将 Microsoft Graph 工具包与 Electron 配合使用

本文介绍如何使用 Microsoft Graph 工具包创建 Electron 应用并将其连接到 Microsoft 365。 完成这些步骤后,你将获得一个 Electron 应用,该应用显示 Microsoft 365 中当前登录用户的即将约会。

创建 Electron 应用

使用 Electron Forge 搭建新的 Electron 应用基架。 这样做会在 TypeScript 中创建一个新的 Electron 应用,这有助于编写更可靠的代码并避免运行时错误。

npm init electron-app@latest mgt-app -- --template=webpack-typescript

将工作目录更改为新创建的应用。

cd mgt-app

确认可以运行应用。

npm start

package.json打开文件,确保电子开发依赖项版本为 28.2.428.2.4 是 所需的对等依赖项的 @microsoft/mgt-electron-provider当前最大版本。

安装包含所有 Microsoft Graph 连接的 Web 组件的“@microsoft/mgt-components”包。

npm i @microsoft/mgt-components

同时安装 @microsoft/mgt-electron-provider@microsoft/mgt-element npm 包。 这些允许你使用 MSAL 为应用提供身份验证,并使用 Microsoft Graph 工具包组件。

npm i @microsoft/mgt-element @microsoft/mgt-electron-provider

创建应用/客户端 ID

在 Microsoft Entra ID 中添加新的应用程序注册以获取客户端 ID

若要在 Microsoft Entra ID 中创建应用程序,需要添加新的应用程序注册,然后配置应用名称和重定向 URI。

若要在 Microsoft Entra ID 中创建应用,请执行以下操作:

  1. 转到Microsoft Entra 管理中心
  2. 展开“标识>”展开“应用程序>”选择“应用注册”。
  3. 在顶部菜单中,选择“ 新建注册 ”按钮。
  4. 输入应用的名称;例如 。 My Electron-App
  5. 对于支持的帐户类型,请选择“任何组织目录中的帐户 (任何Microsoft Entra目录 - 多租户) 和个人 Microsoft 帐户 (,例如 Skype、Xbox)
  6. “重定向 URI” 字段的下拉列表中,选择“ 公共客户端/本机 (移动 & 桌面) ”,然后在“URL”字段中输入 msal://redirect
  7. 通过选择“ 注册 ”按钮确认更改。
  8. 转到应用程序注册。
  9. 验证是否位于“ 概述 ”页上。
  10. “Essentials”部分中,复制“应用程序 (客户端) ID”属性的值。

配置 Microsoft Graph 工具包身份验证提供程序

在预加载脚本中初始化 ContextBridge

从 Electron v12 开始,默认情况下会启用上下文隔离,这是所有应用程序的建议安全设置。 使用上下文隔离,开发人员必须从其main进程中显式公开 API,以便通过 ContextBridge 在呈现器进程中使用。 有关详细信息,请参阅 Electron 文档中的上下文隔离

打开 src/preload.ts 文件并添加以下代码:

import { type IpcRendererEvent, contextBridge, ipcRenderer } from 'electron';
import { AuthenticationProviderOptions } from '@microsoft/microsoft-graph-client';

contextBridge.exposeInMainWorld("main", {
  electronProvider: {
    mgtAuthState: (callback: (event: IpcRendererEvent, authState: string) => void) => ipcRenderer.on('mgtAuthState', callback),
    token: (options?: AuthenticationProviderOptions) => ipcRenderer.invoke('token', options),
    login: () => ipcRenderer.invoke('login'),
    logout: () => ipcRenderer.invoke('logout'),
    approvedScopes: (callback: (event: IpcRendererEvent, scopes: string[]) => void) => ipcRenderer.on('approvedScopes', callback),
  },
});

在呈现器进程中初始化 ElectronContextBridgeProvider

ElectronContextBridgeProvider负责在main进程中与 ElectronAuthenticator (通信,) 请求访问令牌并接收工具包组件工作所需的登录状态的相关信息。

若要在应用程序中使用 Microsoft Graph 工具包组件,必须在打开的浏览器窗口中注册它们。 为此,必须为要使用的每个组件导入寄存器函数。

若要初始化 ElectronContextBridgeProvider 并注册 Microsoft Graph 工具包组件,请将以下代码添加到 src/renderer.ts 文件。

import { Providers } from "@microsoft/mgt-element";
import { registerMgtAgendaComponent, registerMgtLoginComponent } from '@microsoft/mgt-components';
import {
  type IContextBridgeImpl,
} from "@microsoft/mgt-electron-provider/dist/Provider";
import { ElectronContextBridgeProvider } from "@microsoft/mgt-electron-provider/dist/Provider/ElectronContextBridgeProvider";

// this provides typings for the object added to the renderer window by the preload script
declare global {
  interface Window {
    // can be named anything, like "electronApi"
    main: {
      electronProvider: IContextBridgeImpl;
    };
  }
}

// initialize the auth provider globally
const init = () => {
  Providers.globalProvider = new ElectronContextBridgeProvider(window.main.electronProvider);
  registerMgtLoginComponent();
  registerMgtAgendaComponent();
};

init();

在main过程中初始化 ElectronAuthenticator

ElectronAuthenticator负责为 MSAL 身份验证设置配置变量、获取访问令牌并与 通信ElectronContextBridgeProviderElectronAuthenticator在 main 进程中初始化并设置配置变量,例如客户端 ID 和所需范围。

首先,打开 src/index.ts,并从@microsoft/mgt-electron-provider页面顶部导入 ElectronAuthenticatorMsalElectronConfig

import {
  ElectronAuthenticator,
  MsalElectronConfig,
} from "@microsoft/mgt-electron-provider/dist/Authenticator";

然后添加导入 COMMON_AUTHORITY_URL 常量。

import { COMMON_AUTHORITY_URL } from '@microsoft/mgt-electron-provider/dist/Authenticator/Constants';

接下来,在 函数中添加 createWindow() 这些代码行,以在 声明位置 mainWindow 后初始化 ElectronAuthenticator。 将 替换为 <your_client_id> 应用注册中的客户端 ID。

const config: MsalElectronConfig = {
  clientId: "<your_client_id>",
  authority: COMMON_AUTHORITY_URL, // Uses the common auth endpoint
  mainWindow: mainWindow, //This is the BrowserWindow instance that requires authentication
  scopes: [
    "user.read",
    "user.read",
    "people.read",
    "user.readbasic.all",
    "contacts.read",
    "presence.read.all",
    "presence.read",
    "user.read.all",
    "calendars.read",
  ],
};
ElectronAuthenticator.initialize(config);

添加开发内容安全策略

Electron Forge 基架的应用程序包括默认内容安全策略 (CSP) ,该策略禁止从远程服务器提取数据。 出于开发目的,可以添加高度宽松的 CSP。 对于生产应用,需要创建一个可靠的 CSP,使应用程序能够正常运行,同时减少恶意参与者的攻击面。

打开 forge.config.ts 文件,将传递给 WebpackPlugin 构造函数的现有 config 对象替换为以下 config 对象。

{
  mainConfig,
  devContentSecurityPolicy: "default-src * self blob: data: gap:; style-src * self 'unsafe-inline' blob: data: gap:; script-src * 'self' 'unsafe-eval' 'unsafe-inline' blob: data: gap:; object-src * 'self' blob: data: gap:; img-src * self 'unsafe-inline' blob: data: gap:; connect-src self * 'unsafe-inline' blob: data: gap:; frame-src * self blob: data: gap:;",
  renderer: {
    config: rendererConfig,
    entryPoints: [
      {
        html: './src/index.html',
        js: './src/renderer.ts',
        name: 'main_window',
        preload: {
          js: './src/preload.ts',
        },
      },
    ],
  },
}

将组件添加到 HTML 页面

向应用添加一些内容。 现在可以在 index.html 页中使用 Microsoft Graph 工具包组件并显示用户的议程。 将 index.html 页的内容替换为以下内容。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World!</title>
  </head>
  <body>
    <h1>❤️ Hello World! 🦒</h1>
    <p>Welcome to your MGT Electron application.</p>
    <mgt-login></mgt-login>
    <mgt-agenda group-by-day></mgt-agenda>
  </body>
</html>

运行应用

npm start

向应用添加令牌缓存功能,并启用无提示登录 (高级)

MSAL Node 默认支持内存中缓存,并提供 ICachePlugin 接口来执行缓存序列化,但不提供将令牌缓存存储到磁盘的默认方法。 如果需要永久缓存存储来启用无提示登录或跨平台缓存,我们建议使用 MSAL Node 提供的默认实现作为 扩展。 可以导入此插件,并在初始化 ElectronAuthenticator时传递缓存插件的实例。

let config: MsalElectronConfig = {
  ...
  cachePlugin: new PersistenceCachePlugin(filePersistence) //filePersistence is the instance of type IPersistence that you will need to create
};

有关如何实现此功能的详细信息,请参阅 Microsoft 身份验证库-for-js 示例。