Microsoft rozszerzenia uwierzytelniania dla środowiska Node

Microsoft Authentication Extensions for Node oferuje bezpieczne mechanizmy umożliwiające aplikacjom klienckim międzyplatformową serializację i utrwalanie pamięci podręcznej tokenów.

Biblioteka MSAL Node wymaga od deweloperów zaimplementowania własnej logiki do utrwalania pamięci podręcznej tokenów. Rozszerzenia biblioteki MSAL Node mają na celu zapewnienie niezawodnej, bezpiecznej i konfigurowalnej implementacji trwałego przechowywania pamięci podręcznej tokenów w systemach Windows, macOS i Linux dla publicznych aplikacji klienckich (aplikacji klasycznych, aplikacji wiersza polecenia itp.). Zapewnia mechanizmy szyfrowania oraz uzyskiwania dostępu do pamięci podręcznej tokenów przez wiele procesów jednocześnie.

Obsługiwane platformy to Windows, Mac i Linux:

  • Windows — interfejs DPAPI jest używany do szyfrowania.
  • Mac — Pęk kluczy Mac jest używany za pośrednictwem pakietu npm keytar.
  • Linux — biblioteka LibSecret służy do przechowywania w usłudze "Secret Service" za pomocą narzędzia npm keytar.

Code

Tworzenie warstwy trwałości

Interfejs API do tworzenia warstwy trwałości będzie się różnić w zależności od docelowej platformy.

Alternatywnie możesz użyć interfejsu API createPersistence udostępnianego przez PersistenceCreator, ponieważ jest to ogólna warstwa pośrednia, która wybiera odpowiednią metodę utrwalania na podstawie platformy/systemu operacyjnego.

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

Alternatywnie możesz użyć poniższych opcji specyficznych dla platformy:


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 to ścieżka w systemie plików, w którym będzie przechowywany zaszyfrowany plik pamięci podręcznej.
  • dataProtectionScope określa zakres ochrony danych — bieżący użytkownik lub komputer lokalny. Nie potrzebujesz klucza, aby chronić ani nie chronić danych. Jeśli ustawisz zakres na CurrentUser, tylko aplikacje uruchamiane przy użyciu Twoich poświadczeń będą mogły odszyfrować dane; oznacza to jednak, że każda aplikacja uruchamiana przy użyciu Twoich poświadczeń może uzyskać dostęp do chronionych danych. Jeśli ustawisz zakres na LocalMachine, każda aplikacja o pełnym zaufaniu na komputerze może wyłączyć ochronę, dostęp i zmodyfikować dane.
  • optionalEntropy określa hasło lub inną dodatkową entropię używaną do szyfrowania danych.

Element FilePersistenceWithDataProtection używa interfejsów API Win32 CryptProtectData i CryptUnprotectData. Aby uzyskać więcej informacji na temat dataProtectionScope lub optionalEntropy, zapoznaj się z dokumentacją tych interfejsów API.

Wszystkie platformy

Dla wygody dostępny jest mechanizm trwałego przechowywania w niezaszyfrowanym pliku, który działa na wszystkich platformach, choć nie jest zalecany.

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

Jeśli plik lub katalog nie został utworzony, FilePersistence.create() program utworzy plik i wszystkie katalogi w ścieżce cyklicznie. Można to zobaczyć w akcji w FilePersistence.ts

Przekazywanie opcji blokowania do wtyczki Cache do obsługi współbieżności

Utwórz obiekt PersistenceCachePlugin, przekazując obiekt trwałości, który został utworzony w poprzednim kroku.

const { PersistenceCachePlugin } = require("@azure/msal-node-extensions");

const persistenceCachePlugin = new PersistenceCachePlugin(windowsPersistence); // or any of the other ones.

Aby zapewnić współbieżny dostęp przez wiele procesów, rozszerzenia używają blokady opartej na plikach. Liczbę ponowień i opóźnienie między ponowieniami podczas uzyskiwania blokady można skonfigurować za pomocą 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
        },
    });

Ustawianie elementu PersistenceCachePlugin w konfiguracji MSAL Node PublicClientApplication (z przykładem)

Podsumowując, gdy masz element PersistenceCachePlugin, możesz ustawić go w obiekcie MSAL Node PublicClientApplication, ustawiając go jako część obiektu konfiguracji, jak pokazano poniżej.

import { PublicClientApplication } from "@azure/msal-node";

const publicClientConfig = {
    auth: {
        clientId: "",
        authority: "",
    },
    cache: {
        cachePlugin: persistenceCachePlugin
    },
};

const pca = new PublicClientApplication(publicClientConfig);

Przykład (dla aplikacji desktopowej 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
};

Uwaga dla deweloperów Electron

Przykład aplikacji Electron: ten przykład pokazuje, jak zintegrować bibliotekę msal-node-extensions z aplikacją Electron spakowaną przy użyciu webpacka.

Jeśli używasz tego rozszerzenia dla narzędzia Electron, może wystąpić błąd podobny do następującego:

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...."

Ten błąd jest prawdopodobnie spowodowany Node.js różnicami wersji między projektem Electron a rozszerzeniem. Można to rozwiązać poprzez ponowne zbudowanie pakietu, wykonując następujące czynności:

  • Zainstaluj electron-rebuild za pomocą polecenia npm i -D electron-rebuild , jeśli jeszcze go nie zainstalowano.
  • Usuń packages-lock.json z projektu, jeśli istnieje
  • Uruchom ./node_modules/.bin/electron-rebuild

Przykłady

  1. Przykład Electron-webpack do utrwalania danych
  2. Przykład rozszerzeń biblioteki Msal-Node