Node 的 Microsoft 身份验证扩展为客户端应用程序提供安全机制,用于执行跨平台令牌缓存序列化和持久性。
MSAL Node 要求开发人员实现自己的逻辑来保存令牌缓存。 MSAL Node 扩展旨在为公共客户端应用程序(桌面客户端、CLI 应用程序等)提供跨 Windows、Mac 和 Linux 的可靠、安全且可配置的令牌缓存坚持性实现。 它提供了一种机制,用于同时通过多个进程加密和访问令牌缓存。
支持的平台Windows、Mac 和 Linux:
- Windows - DPAPI 用于加密。
- MAC - MAC 密钥链通过 npm keytar 使用。
- Linux - LibSecret 用于通过 npm keytar 将内容存储在“Secret Service”中。
Code
创建持久性层
用于创建持久性层的 API 将因目标平台而异。
或者,可以使用 createPersistencePersistenceCreator 中的 API 作为泛型包装器,并根据平台/OS 选择适当的持久性方法。
const { PublicClientApplication } = require("@azure/msal-node");
const {
DataProtectionScope,
PersistenceCreator,
PersistenceCachePlugin,
} = require("@azure/msal-node-extensions");
const persistence = await PersistenceCreator.createPersistence({
cachePath: "path/to/cache/file.json",
dataProtectionScope: DataProtectionScope.CurrentUser,
serviceName: "test-msal-electron-service",
accountName: "test-msal-electron-account",
usePlaintextFileOnLinux: false,
});
// Use the persistence object to initialize an MSAL PublicClientApplication with cachePlugin
const pca = new PublicClientApplication({
auth: {
clientId: "CLIENT_ID_HERE",
},
cache: {
cachePlugin: new PersistenceCachePlugin(persistence);
},
});
或者,可以使用以下特定于平台的选项:
const { FilePersistenceWithDataProtection, DataProtectionScope } = require("@azure/msal-node-extensions");
const { PublicClientApplication } = require("@azure/msal-node");
const cachePath = "path/to/cache/file.json";
const dataProtectionScope = DataProtectionScope.CurrentUser;
const optionalEntropy = ""; //specifies password or other additional entropy used to encrypt the data.
const windowsPersistence = await FilePersistenceWithDataProtection.create(cachePath, dataProtectionScope, optionalEntropy);
// Use the persistence object to initialize an MSAL PublicClientApplication with cachePlugin
const pca = new PublicClientApplication({
auth: {
clientId: "CLIENT_ID_HERE",
},
cache: {
cachePlugin: new PersistenceCachePlugin(windowsPersistence);
},
});
-
cachePath是将存储加密缓存文件的文件系统中的路径。 -
dataProtectionScope指定数据保护的范围,即当前用户或本地计算机。 不需要密钥来保护或取消保护数据。 如果将范围设置为 CurrentUser,则只有凭据上运行的应用程序才能取消保护数据;但是,这意味着在凭据上运行的任何应用程序都可以访问受保护的数据。 如果将范围设置为 LocalMachine,则计算机上的任何完全信任应用程序都可以取消保护、访问和修改数据。 -
optionalEntropy指定用于加密数据的密码或其他附加信息量。
FilePersistenceWithDataProtection 使用 Win32 CryptProtectData 和 CryptUnprotectData API。 有关 dataProtectionScope 或 optionalEntropy 的详细信息,请参阅这些 API 的文档。
所有平台
为了方便起见,提供了适用于所有平台的未加密文件持久化方式,但不推荐使用该方式。
const { FilePersistence } = require("@azure/msal-node-extensions");
const filePath = "path/to/cache/file.json";
const filePersistence = await FilePersistence.create(filePath, loggerOptions);
// Pass the persistence to msal config's cachePlugin
const pca = new PublicClientApplication({
auth: {
clientId: "CLIENT_ID_HERE",
},
cache: {
cachePlugin: new PersistenceCachePlugin(filePersistence);
},
});
如果未创建文件或目录, FilePersistence.create() 则会以递归方式创建该文件和路径中的任何目录。 这可以在FilePersistence.ts中看到其实际应用
将锁定选项传递到缓存插件以实现并发
通过传入上一步创建的持久性对象,创建 PersistenceCachePlugin。
const { PersistenceCachePlugin } = require("@azure/msal-node-extensions");
const persistenceCachePlugin = new PersistenceCachePlugin(windowsPersistence); // or any of the other ones.
为了支持多个进程的并发访问,扩展使用基于文件的锁。 可以配置通过 CrossPlatformLockOptions 获取锁时的重试次数和重试延迟。
const {
PersistenceCreator,
PersistenceCachePlugin,
} = require("@azure/msal-node-extensions");
const lockOptions = {
retryNumber: 100,
retryDelay: 50
}
const persistence = await PersistenceCreator.createPersistence(persistenceConfiguration);
const persistenceCachePlugin = new PersistenceCachePlugin(persistence, lockOptions); // or any of the other ones
const pca = new PublicClientApplication({
auth: {
clientId: "CLIENT_ID_HERE",
},
cache: {
cachePlugin: persistenceCachePlugin
},
});
在 MSAL 节点 PublicClientApplication 配置上设置 PersistenceCachePlugin (示例)
总之,一旦有了 PersistenceCachePlugin,就可以将其设置到 MSAL Node PublicClientApplication 上,方法是按如下所示将其作为 配置 对象的一部分进行设置。
import { PublicClientApplication } from "@azure/msal-node";
const publicClientConfig = {
auth: {
clientId: "",
authority: "",
},
cache: {
cachePlugin: persistenceCachePlugin
},
};
const pca = new PublicClientApplication(publicClientConfig);
示例(适用于 Electron node-js 桌面应用):-
authConfig.js:-
const AAD_ENDPOINT_HOST = "https://login.microsoftonline.com/"; // include the trailing slash
const REDIRECT_URI = "ENTER_REDIRECT_URI";
const cachePath = "path/to/cache/file.json";
/*define persistence config based on the appropriate persistence you are using(e.g- FilePersistenceWithDataProtection, generic PersistenceCreateor, etc)*/
//defining persistence config for PersistenceCreator
const persistenceConfiguration = {
cachePath,
dataProtectionScope: DataProtectionScope.CurrentUser,
serviceName: "test-msal-electron-service",
accountName: "test-msal-electron-account",
usePlaintextFileOnLinux: false,
}
const msalConfig = {
auth: {
clientId: "CLIENT_ID_HERE",
authority: `${AAD_ENDPOINT_HOST}TENANT_ID_HERE`,
},
cache: {
cachePlugin: null // set later in main.js as shown above
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: LogLevel.Verbose,
},
},
};
...
module.exports = {
msalConfig: msalConfig,
protectedResources: protectedResources,
REDIRECT_URI: REDIRECT_URI,
persistenceConfiguration
};
电子开发人员注意事项
Electron 示例:此 示例 演示如何将 msal-node-extensions 库集成到经过 webpack 打包的 Electron 应用程序中。
如果要将此扩展用于 Electron,则可能会遇到类似于下面的错误:
Uncaught Exception:
Error: The module
"<path-to-project>\node_modules\...\dpapi.node" was compiled against a different Node.js version using NODE_MODULE_VERSION 85. This version of Node.js requires NODE_MODULE_VERSION 80. Please try re-compiling or re-installing the module...."
此错误可能是由于电子项目和扩展之间的 Node.js 版本差异。 可通过以下步骤重新生成包来处理此问题:
- 如果尚未安装
electron-rebuild,请使用命令npm i -D electron-rebuild进行安装。 - 如果存在,请从项目中移除
packages-lock.json -
./node_modules/.bin/electron-rebuild运行