Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ebben az oktatóanyagban egy Electron asztali alkalmazást hoz létre, amely bejelentkezteti a felhasználókat, és a PKCE-vel ellátott engedélyezési kódfolyamatot használva hívja meg a Microsoft Graphot. Az asztali alkalmazás, amelyet építesz, a Microsoft Authentication Library-t (MSAL) használja Node.js-hez.
A következőkre vonatkozik:
Munkaerő-bérlők (további információ)
Ebben az útmutatóban Ön:
- Az alkalmazás regisztrálása az Azure Portalon
- Electron asztali alkalmazásprojekt létrehozása
- Hitelesítési logika hozzáadása az alkalmazáshoz
- Metódus hozzáadása webes API meghívásához
- Alkalmazásregisztráció részleteinek hozzáadása
- Az alkalmazás tesztelése
Előfeltételek
- Munkaerőt igénybe vevő. Használhatja az alapértelmezett címtárat, vagy beállíthat egy új bérlőt.
- Regisztráljon egy új alkalmazást a Microsoft Entra felügyeleti központban, amely csak ebben a szervezeti címtárban lévő fiókokhoz van konfigurálva. További részletekért tekintse meg az alkalmazás regisztrálását . Jegyezze fel a következő értékeket az alkalmazás áttekintési oldaláról későbbi használatra:
- Alkalmazás (ügyfél) azonosítója
- Címtár (ügyfél) azonosítója
- Következő átirányítási URI-k hozzáadása a mobil- és asztali alkalmazások platform konfigurációval. Tekintse meg a Hogyan adható hozzá egy átirányítási URI az alkalmazásban című részt további részletekért.
-
Átirányítási URI:
http://localhost
-
Átirányítási URI:
- Node.js
- Elektron
- Visual Studio Code vagy más kódszerkesztő
A projekt létrehozása
Megjegyzés:
Az oktatóanyagban szereplő elektronminta kifejezetten az MSAL-csomóponttal való együttműködésre lett kialakítva. Az MSAL-böngésző nem támogatott az Electron-alkalmazásokban. Győződjön meg arról, hogy a projekt helyes beállításához hajtsa végre az alábbi lépéseket.
Hozzon létre egy mappát az alkalmazás üzemeltetéséhez, például az ElectronDesktopApphoz.
Először váltson a projektkönyvtárra a terminálban, majd futtassa a következő
npmparancsokat:npm init -y npm install --save @azure/msal-node @microsoft/microsoft-graph-client isomorphic-fetch bootstrap jquery popper.js npm install --save-dev electron@20.0.0Ezután hozzon létre egy App nevű mappát. Ebben a mappában hozzon létre egy index.html nevű fájlt, amely felhasználói felületként szolgál. Adja hozzá a következő kódot:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no"> <meta http-equiv="Content-Security-Policy" content="script-src 'self'" /> <title>MSAL Node Electron Sample App</title> <!-- adding Bootstrap 4 for UI components --> <link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css"> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <a class="navbar-brand">Microsoft identity platform</a> <div class="btn-group ml-auto dropleft"> <button type="button" id="signIn" class="btn btn-secondary" aria-expanded="false"> Sign in </button> <button type="button" id="signOut" class="btn btn-success" hidden aria-expanded="false"> Sign out </button> </div> </nav> <br> <h5 class="card-header text-center">Electron sample app calling MS Graph API using MSAL Node</h5> <br> <div class="row" style="margin:auto"> <div id="cardDiv" class="col-md-6" style="display:none; margin:auto"> <div class="card text-center"> <div class="card-body"> <h5 class="card-title" id="WelcomeMessage">Please sign-in to see your profile and read your mails </h5> <div id="profileDiv"></div> <br> <br> <button class="btn btn-primary" id="seeProfile">See Profile</button> </div> </div> </div> </div> <!-- importing bootstrap.js and supporting js libraries --> <script src="../node_modules/jquery/dist/jquery.js"></script> <script src="../node_modules/popper.js/dist/umd/popper.js"></script> <script src="../node_modules/bootstrap/dist/js/bootstrap.js"></script> <!-- importing app scripts | load order is important --> <script src="./renderer.js"></script> </body> </html>Ezután hozzon létre main.js nevű fájlt, és adja hozzá a következő kódot:
/* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ const path = require("path"); const { app, ipcMain, BrowserWindow } = require("electron"); const AuthProvider = require("./AuthProvider"); const { IPC_MESSAGES } = require("./constants"); const { protectedResources, msalConfig } = require("./authConfig"); const getGraphClient = require("./graph"); let authProvider; let mainWindow; function createWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, "preload.js") }, }); authProvider = new AuthProvider(msalConfig); } app.on("ready", () => { createWindow(); mainWindow.loadFile(path.join(__dirname, "./index.html")); }); app.on("window-all-closed", () => { app.quit(); }); app.on('activate', () => { // On OS X it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); // Event handlers ipcMain.on(IPC_MESSAGES.LOGIN, async () => { const account = await authProvider.login(); await mainWindow.loadFile(path.join(__dirname, "./index.html")); mainWindow.webContents.send(IPC_MESSAGES.SHOW_WELCOME_MESSAGE, account); }); ipcMain.on(IPC_MESSAGES.LOGOUT, async () => { await authProvider.logout(); await mainWindow.loadFile(path.join(__dirname, "./index.html")); }); ipcMain.on(IPC_MESSAGES.GET_PROFILE, async () => { const tokenRequest = { scopes: protectedResources.graphMe.scopes }; const tokenResponse = await authProvider.getToken(tokenRequest); const account = authProvider.account; await mainWindow.loadFile(path.join(__dirname, "./index.html")); const graphResponse = await getGraphClient(tokenResponse.accessToken) .api(protectedResources.graphMe.endpoint).get(); mainWindow.webContents.send(IPC_MESSAGES.SHOW_WELCOME_MESSAGE, account); mainWindow.webContents.send(IPC_MESSAGES.SET_PROFILE, graphResponse); });
A fenti kódrészletben inicializálunk egy Elektron főablak objektumot, és létrehozunk néhány eseménykezelőt az Elektron ablakkal való interakcióhoz. Emellett importáljuk a konfigurációs paramétereket, példányosítjuk az authProvider osztályt a bejelentkezés, a kijelentkezés és a jogkivonatok beszerzésének kezeléséhez, és meghívjuk a Microsoft Graph API-t.
Ugyanabban a mappában (appban) hozzon létre egy másik fájlt renderer.js, és adja hozzá a következő kódot:
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License /** * The renderer API is exposed by the preload script found in the preload.ts * file in order to give the renderer access to the Node API in a secure and * controlled way */ const welcomeDiv = document.getElementById('WelcomeMessage'); const signInButton = document.getElementById('signIn'); const signOutButton = document.getElementById('signOut'); const seeProfileButton = document.getElementById('seeProfile'); const cardDiv = document.getElementById('cardDiv'); const profileDiv = document.getElementById('profileDiv'); window.renderer.showWelcomeMessage((event, account) => { if (!account) return; cardDiv.style.display = 'initial'; welcomeDiv.innerHTML = `Welcome ${account.name}`; signInButton.hidden = true; signOutButton.hidden = false; }); window.renderer.handleProfileData((event, graphResponse) => { if (!graphResponse) return; console.log(`Graph API responded at: ${new Date().toString()}`); setProfile(graphResponse); }); // UI event handlers signInButton.addEventListener('click', () => { window.renderer.sendLoginMessage(); }); signOutButton.addEventListener('click', () => { window.renderer.sendSignoutMessage(); }); seeProfileButton.addEventListener('click', () => { window.renderer.sendSeeProfileMessage(); }); const setProfile = (data) => { if (!data) return; profileDiv.innerHTML = ''; const title = document.createElement('p'); const email = document.createElement('p'); const phone = document.createElement('p'); const address = document.createElement('p'); title.innerHTML = '<strong>Title: </strong>' + data.jobTitle; email.innerHTML = '<strong>Mail: </strong>' + data.mail; phone.innerHTML = '<strong>Phone: </strong>' + data.businessPhones[0]; address.innerHTML = '<strong>Location: </strong>' + data.officeLocation; profileDiv.appendChild(title); profileDiv.appendChild(email); profileDiv.appendChild(phone); profileDiv.appendChild(address); }
A renderelő metódusokat úgy teszi elérhetővé az előretöltési szkript, amely a preload.js fájlban található, hogy a renderelő biztonságos és szabályozott módon férhessen hozzá a Node API.
Ezután hozzon létre egy új fájlt preload.js , és adja hozzá a következő kódot:
// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License const { contextBridge, ipcRenderer } = require('electron'); /** * This preload script exposes a "renderer" API to give * the Renderer process controlled access to some Node APIs * by leveraging IPC channels that have been configured for * communication between the Main and Renderer processes. */ contextBridge.exposeInMainWorld('renderer', { sendLoginMessage: () => { ipcRenderer.send('LOGIN'); }, sendSignoutMessage: () => { ipcRenderer.send('LOGOUT'); }, sendSeeProfileMessage: () => { ipcRenderer.send('GET_PROFILE'); }, handleProfileData: (func) => { ipcRenderer.on('SET_PROFILE', (event, ...args) => func(event, ...args)); }, showWelcomeMessage: (func) => { ipcRenderer.on('SHOW_WELCOME_MESSAGE', (event, ...args) => func(event, ...args)); }, });
Ez az előre betöltési szkript egy renderelő API-t tesz elérhetővé, amely lehetővé teszi, hogy a renderelő folyamat által szabályozott hozzáférést biztosítson néhányhoz Node APIs a fő és a renderelő folyamatok közötti kommunikációhoz konfigurált IPC-csatornák alkalmazásával.
Végül hozzon létre egy constants.js nevű fájlt, amely az alkalmazásesemények leírásához tárolja a sztringállandókat:
/* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ const IPC_MESSAGES = { SHOW_WELCOME_MESSAGE: 'SHOW_WELCOME_MESSAGE', LOGIN: 'LOGIN', LOGOUT: 'LOGOUT', GET_PROFILE: 'GET_PROFILE', SET_PROFILE: 'SET_PROFILE', } module.exports = { IPC_MESSAGES: IPC_MESSAGES, }
Most már rendelkezik egy egyszerű grafikus felhasználói felületsel és interakciókkal az Electron-alkalmazáshoz. Az oktatóanyag többi részének elvégzése után a projekt fájl- és mappaszerkezetének a következőhöz hasonlóan kell kinéznie:
ElectronDesktopApp/
├── App
│ ├── AuthProvider.js
│ ├── constants.js
│ ├── graph.js
│ ├── index.html
| ├── main.js
| ├── preload.js
| ├── renderer.js
│ ├── authConfig.js
├── package.json
Hitelesítési logika hozzáadása az alkalmazáshoz
Az Alkalmazás mappában hozzon létre egy AuthProvider.js nevű fájlt. A AuthProvider.js fájl egy hitelesítési szolgáltatói osztályt tartalmaz, amely mSAL-csomópont használatával kezeli a bejelentkezést, a kijelentkezéseket, a jogkivonatok beszerzését, a fiókválasztást és a kapcsolódó hitelesítési feladatokat. Adja hozzá a következő kódot:
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
const { PublicClientApplication, InteractionRequiredAuthError } = require('@azure/msal-node');
const { shell } = require('electron');
class AuthProvider {
msalConfig
clientApplication;
account;
cache;
constructor(msalConfig) {
/**
* Initialize a public client application. For more information, visit:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/initialize-public-client-application.md
*/
this.msalConfig = msalConfig;
this.clientApplication = new PublicClientApplication(this.msalConfig);
this.cache = this.clientApplication.getTokenCache();
this.account = null;
}
async login() {
const authResponse = await this.getToken({
// If there are scopes that you would like users to consent up front, add them below
// by default, MSAL will add the OIDC scopes to every token request, so we omit those here
scopes: [],
});
return this.handleResponse(authResponse);
}
async logout() {
if (!this.account) return;
try {
/**
* If you would like to end the session with AAD, use the logout endpoint. You'll need to enable
* the optional token claim 'login_hint' for this to work as expected. For more information, visit:
* https://learn.microsoft.com/azure/active-directory/develop/v2-protocols-oidc#send-a-sign-out-request
*/
if (this.account.idTokenClaims.hasOwnProperty('login_hint')) {
await shell.openExternal(`${this.msalConfig.auth.authority}/oauth2/v2.0/logout?logout_hint=${encodeURIComponent(this.account.idTokenClaims.login_hint)}`);
}
await this.cache.removeAccount(this.account);
this.account = null;
} catch (error) {
console.log(error);
}
}
async getToken(tokenRequest) {
let authResponse;
const account = this.account || (await this.getAccount());
if (account) {
tokenRequest.account = account;
authResponse = await this.getTokenSilent(tokenRequest);
} else {
authResponse = await this.getTokenInteractive(tokenRequest);
}
return authResponse || null;
}
async getTokenSilent(tokenRequest) {
try {
return await this.clientApplication.acquireTokenSilent(tokenRequest);
} catch (error) {
if (error instanceof InteractionRequiredAuthError) {
console.log('Silent token acquisition failed, acquiring token interactive');
return await this.getTokenInteractive(tokenRequest);
}
console.log(error);
}
}
async getTokenInteractive(tokenRequest) {
try {
const openBrowser = async (url) => {
await shell.openExternal(url);
};
const authResponse = await this.clientApplication.acquireTokenInteractive({
...tokenRequest,
openBrowser,
successTemplate: '<h1>Successfully signed in!</h1> <p>You can close this window now.</p>',
errorTemplate: '<h1>Oops! Something went wrong</h1> <p>Check the console for more information.</p>',
});
return authResponse;
} catch (error) {
throw error;
}
}
/**
* Handles the response from a popup or redirect. If response is null, will check if we have any accounts and attempt to sign in.
* @param response
*/
async handleResponse(response) {
if (response !== null) {
this.account = response.account;
} else {
this.account = await this.getAccount();
}
return this.account;
}
/**
* Calls getAllAccounts and determines the correct account to sign into, currently defaults to first account found in cache.
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md
*/
async getAccount() {
const currentAccounts = await this.cache.getAllAccounts();
if (!currentAccounts) {
console.log('No accounts detected');
return null;
}
if (currentAccounts.length > 1) {
// Add choose account code here
console.log('Multiple accounts detected, need to add choose account code.');
return currentAccounts[0];
} else if (currentAccounts.length === 1) {
return currentAccounts[0];
} else {
return null;
}
}
}
module.exports = AuthProvider;
A fenti kódrészletben először inicializáltuk az MSAL-csomópontot PublicClientApplication egy konfigurációs objektum (msalConfig) átadásával. Ezután közzétettük logina logoutgetToken fő modul (main.js) által meghívandó metódusokat. Az login és getToken használatával az MSAL Node acquireTokenInteractive nyilvános API segítségével szerzünk be azonosító- és hozzáférési jogkivonatokat.
Microsoft Graph SDK hozzáadása
Hozzon létre egy graph.js nevű fájlt. A graph.js fájl a Microsoft Graph SDK-ügyfél egy példányát tartalmazza, amely megkönnyíti az adatok elérését a Microsoft Graph API-n az MSAL Node által beszerzett hozzáférési jogkivonat használatával:
const { Client } = require('@microsoft/microsoft-graph-client');
require('isomorphic-fetch');
/**
* Creating a Graph client instance via options method. For more information, visit:
* https://github.com/microsoftgraph/msgraph-sdk-javascript/blob/dev/docs/CreatingClientInstance.md#2-create-with-options
* @param {String} accessToken
* @returns
*/
const getGraphClient = (accessToken) => {
// Initialize Graph client
const graphClient = Client.init({
// Use the provided access token to authenticate requests
authProvider: (done) => {
done(null, accessToken);
},
});
return graphClient;
};
module.exports = getGraphClient;
Alkalmazásregisztráció részleteinek hozzáadása
Hozzon létre egy környezeti fájlt a jogkivonatok beszerzésekor használt alkalmazásregisztrációs adatok tárolásához. Ehhez hozzon létre egy authConfig.js nevű fájlt a minta gyökérmappájában (ElectronDesktopApp), és adja hozzá a következő kódot:
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
const { LogLevel } = require("@azure/msal-node");
/**
* Configuration object to be passed to MSAL instance on creation.
* For a full list of MSAL.js configuration parameters, visit:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md
*/
const AAD_ENDPOINT_HOST = "Enter_the_Cloud_Instance_Id_Here"; // include the trailing slash
const msalConfig = {
auth: {
clientId: "Enter_the_Application_Id_Here",
authority: `${AAD_ENDPOINT_HOST}Enter_the_Tenant_Info_Here`,
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: LogLevel.Verbose,
},
},
};
/**
* Add here the endpoints and scopes when obtaining an access token for protected web APIs. For more information, see:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/resources-and-scopes.md
*/
const GRAPH_ENDPOINT_HOST = "Enter_the_Graph_Endpoint_Here"; // include the trailing slash
const protectedResources = {
graphMe: {
endpoint: `${GRAPH_ENDPOINT_HOST}v1.0/me`,
scopes: ["User.Read"],
}
};
module.exports = {
msalConfig: msalConfig,
protectedResources: protectedResources,
};
Töltse ki ezeket a részleteket az Azure alkalmazásregisztrációs portálról beszerzett értékekkel:
-
Enter_the_Tenant_Id_hereaz alábbiak egyikének kell lennie:- Ha az alkalmazás támogatja a szervezeti címtárban lévő fiókokat, cserélje le ezt az értéket a bérlőazonosítóra vagy a bérlő nevére. Például:
contoso.microsoft.com. - Ha az alkalmazás bármely szervezeti könyvtárban támogatja a fiókokat, cserélje le ezt az értéket a következőre
organizations: . - Ha az alkalmazás bármely szervezeti címtárban és személyes Microsoft-fiókban támogatja a fiókokat, cserélje le ezt az értéket a következőre
common: . - Ha szeretné korlátozni a támogatást kizárólag a személyes Microsoft-fiókokra, cserélje le ezt az értéket ezzel: .
- Ha az alkalmazás támogatja a szervezeti címtárban lévő fiókokat, cserélje le ezt az értéket a bérlőazonosítóra vagy a bérlő nevére. Például:
-
Enter_the_Application_Id_Here: A regisztrált alkalmazás (ügyfél) azonosítója . -
Enter_the_Cloud_Instance_Id_Here: Az az Azure-felhőpéldány, amelyben az alkalmazás regisztrálva van.- A fő (vagy globális) Azure-felhőbe írja be a következőt
https://login.microsoftonline.com/: . - A nemzeti felhők (például Kína) esetében a nemzeti felhőkben megtalálhatja a megfelelő értékeket.
- A fő (vagy globális) Azure-felhőbe írja be a következőt
-
Enter_the_Graph_Endpoint_Herea Microsoft Graph API azon példánya, amellyel az alkalmazásnak kommunikálnia kell.-
A globális Microsoft Graph API-végpont esetében cserélje le a sztring mindkét példányát a következőre
https://graph.microsoft.com/: . - A nemzeti felhőbeli üzembe helyezések végpontjait lásd a Microsoft Graph dokumentációjában található "Nemzeti felhőbeli üzembe helyezések" részben.
-
A globális Microsoft Graph API-végpont esetében cserélje le a sztring mindkét példányát a következőre
Az alkalmazás tesztelése
Befejezte az alkalmazás létrehozását, és készen áll az Electron asztali alkalmazás elindítására és az alkalmazás működésének tesztelésére.
- Indítsa el az alkalmazást a következő parancs futtatásával a projektmappában:
electron App/main.js
- Az alkalmazás főablakában látnia kell a index.html fájl tartalmát és a Bejelentkezés gombot.
Bejelentkezés tesztelése és kijelentkezés
A index.html fájl betöltése után válassza a Bejelentkezés lehetőséget. A rendszer kéri, hogy jelentkezzen be a Microsoft Identity platformmal.
Ha ön hozzájárul a kért engedélyekhez, a webalkalmazások megjelenítik a felhasználónevet, és sikeres bejelentkezést jeleznek:
Webes API-hívás tesztelése
A bejelentkezés után válassza a Profil megtekintése lehetőséget a Microsoft Graph API-nak küldött hívás válaszában visszaadott felhasználói profiladatok megtekintéséhez. A hozzájárulást követően a válaszban visszaadott profiladatokat fogja megtekinteni:
Az alkalmazás működése
Amikor egy felhasználó először választja ki a Bejelentkezés gombot, a acquireTokenInteractive MSAL Node metódusa. Ez a módszer átirányítja a felhasználót a bejelentkezésre a Microsoft Identitásplatform végponttal, ellenőrzi a felhasználó hitelesítő adatait, beolvas egy engedélyezési kódot, majd kicseréli a kódot egy azonosító jogkivonatra, hozzáférési jogkivonatra és frissítési jogkivonatra. Az MSAL Node ezeket a jogkivonatokat is tárolja gyorsítótárban későbbi használatra.
Az azonosító alapvető információkat tartalmaz a felhasználóról, például a megjelenített nevét. A hozzáférési jogkivonat élettartama korlátozott, és 24 óra elteltével lejár. Ha ezeket a jogkivonatokat a védett erőforrás eléréséhez szeretné használni, a háttérkiszolgálónak ellenőriznie kell , hogy a jogkivonatot az alkalmazás érvényes felhasználójának adta-e ki.
Az oktatóanyagban létrehozott asztali alkalmazás REST-hívást indít a Microsoft Graph API-hoz egy hozzáférési jogkivonatot használva a kérésfejlécben (RFC 6750).
A Microsoft Graph API-hoz a user.read hatókörnek be kell olvasnia egy felhasználó profilját. Alapértelmezés szerint ez a hatókör automatikusan hozzáadódik minden olyan alkalmazáshoz, amely regisztrálva van az Azure Portalon. A Microsoft Graph egyéb API-jai és a háttérkiszolgálóhoz tartozó egyéni API-k további hatóköröket igényelhetnek. A Microsoft Graph API-nak például a Mail.Read hatókörre van szüksége a felhasználó e-mailjeinek listázásához.
Hatókörök hozzáadásakor előfordulhat, hogy a felhasználók egy másik hozzájárulás megadását kérik a hozzáadott hatókörökhöz.
Súgó és támogatás
Ha segítségre van szüksége, szeretne jelentést készíteni egy problémáról, vagy szeretne többet megtudni a támogatási lehetőségekről, olvassa el a súgót és a fejlesztők támogatását.
Következő lépések
Ha részletesebben szeretne megismerkedni a Node.js és az Electron asztali alkalmazásfejlesztésével a Microsoft Identitásplatform, tekintse meg többrészes forgatókönyv-sorozatunkat: