Anmerkung
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Gilt für:
Mitarbeitermandanten
Externe Mandanten (weitere Informationen)
In diesem Lernprogramm fügen Sie Ihrer Node/Express-Web-App Anmelde- und Abmeldelogik hinzu. Mit diesem Code können Sie Benutzer und Benutzerinnen in Ihrer kundenorientierten App bei einem externen Mandanten oder Mitarbeitende bei einem Mitarbeitermandanten anmelden.
Dieses Lernprogramm ist Teil 2 der dreiteiligen Lernprogrammreihe.
In diesem Tutorial führen Sie Folgendes durch:
- Hinzufügen von Anmelde- und Abmeldelogik
- ID-Token-Ansprüche anzeigen
- Führen Sie die App aus, und testen Sie die Anmelde- und Abmeldeerfahrung.
Voraussetzungen
- Führen Sie die Schritte im Lernprogramm aus: Einrichten einer Node.js Web-App zum Anmelden von Benutzern mithilfe der Microsoft Identity Platform.
Erstellen des MSAL-Konfigurationsobjekts
Öffnen Sie in Ihrem Code-Editor die Datei authConfig.js, und fügen Sie dann den folgenden Code hinzu:
require('dotenv').config();
const TENANT_SUBDOMAIN = process.env.TENANT_SUBDOMAIN || 'Enter_the_Tenant_Subdomain_Here';
const REDIRECT_URI = process.env.REDIRECT_URI || 'http://localhost:3000/auth/redirect';
const POST_LOGOUT_REDIRECT_URI = process.env.POST_LOGOUT_REDIRECT_URI || 'http://localhost:3000';
const GRAPH_ME_ENDPOINT = process.env.GRAPH_API_ENDPOINT + "v1.0/me" || 'Enter_the_Graph_Endpoint_Here';
/**
* Configuration object to be passed to MSAL instance on creation.
* For a full list of MSAL Node configuration parameters, visit:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md
*/
const msalConfig = {
auth: {
clientId: process.env.CLIENT_ID || 'Enter_the_Application_Id_Here', // 'Application (client) ID' of app registration in Azure portal - this value is a GUID
//For external tenant
authority: process.env.AUTHORITY || `https://${TENANT_SUBDOMAIN}.ciamlogin.com/`, // replace "Enter_the_Tenant_Subdomain_Here" with your tenant name
//For workforce tenant
//authority: process.env.CLOUD_INSTANCE + process.env.TENANT_ID
clientSecret: process.env.CLIENT_SECRET || 'Enter_the_Client_Secret_Here', // Client secret generated from the app registration in Azure portal
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: 'Info',
},
},
};
module.exports = {
msalConfig,
REDIRECT_URI,
POST_LOGOUT_REDIRECT_URI,
TENANT_SUBDOMAIN,
GRAPH_ME_ENDPOINT
};
Das msalConfig-Objekt enthält eine Reihe von Konfigurationsoptionen, die von Ihnen zum Anpassen des Verhaltens Ihrer Authentifizierungsflows verwendet werden.
Ersetzen Sie Folgendes in Ihrer authConfig.js-Datei:
Enter_the_Application_Id_Heremit der Anwendungs-ID (Client) der App, die Sie zuvor registriert haben.Enter_the_Tenant_Subdomain_Here, und ersetzen Sie diese durch die Unterdomäne des externen Verzeichnisses (Mandant). Wenn Ihre primäre Mandantendomäne z. B.contoso.onmicrosoft.comist, verwenden Siecontoso. Wenn Sie Ihren Mandantennamen nicht kennen, finden Sie weitere Informationen unter Auslesen der Details Ihres Mandanten. Dieser Wert ist nur für externe Mandanten erforderlich.Enter_the_Client_Secret_Heredurch den Wert des App-Geheimnisses, den Sie zuvor kopiert haben.Enter_the_Graph_Endpoint_Heremit der Microsoft Graph-API-Cloudinstanz, die Ihre App aufrufen wird. Verwenden Sie den Werthttps://graph.microsoft.com/(fügen Sie den nachgestellten Schrägstrich ein)
Wenn Sie die env-Datei verwenden, um Ihre Konfigurationsinformationen zu speichern:
Öffnen Sie in Ihrem Code-Editor die env-Datei , und fügen Sie dann den folgenden Code hinzu.
CLIENT_ID=Enter_the_Application_Id_Here TENANT_SUBDOMAIN=Enter_the_Tenant_Subdomain_Here CLOUD_INSTANCE="Enter_the_Cloud_Instance_Id_Here" # cloud instance string should end with a trailing slash TENANT_ID=Enter_the_Tenant_ID_here CLIENT_SECRET=Enter_the_Client_Secret_Here REDIRECT_URI=http://localhost:3000/auth/redirect POST_LOGOUT_REDIRECT_URI=http://localhost:3000 GRAPH_API_ENDPOINT=Enter_the_Graph_Endpoint_Here # graph api endpoint string should end with a trailing slash EXPRESS_SESSION_SECRET=Enter_the_Express_Session_Secret_Here # express session secret, just any random textErsetzen Sie den Platzhalter:
Enter_the_Application_Id_Here,Enter_the_Tenant_Subdomain_HereundEnter_the_Client_Secret_Herewie bereits erläutert.Enter_the_Cloud_Instance_Id_Heremit der Azure-Cloudinstanz, in der Ihre Anwendung registriert ist. Verwenden Siehttps://login.microsoftonline.com/als Wert (schließen Sie den nachfolgenden Schrägstrich ein). Dieser Wert wird nur für den Workforce-Tenant benötigt.Enter_the_Tenant_ID_heremit der Mandanten-ID oder der primären Domäne der Mitarbeitenden, z. B. aaaabbbb-0000-cccc-1111-dddd2222eeee oder contoso.microsoft.com. Dieser Wert wird nur für den Workforce-Tenant benötigt.
Sie exportieren msalConfig, REDIRECT_URI, und TENANT_SUBDOMAINGRAPH_ME_ENDPOINTPOST_LOGOUT_REDIRECT_URI Variablen in der authConfig.js Datei, um sie in anderen Dateien zugänglich zu machen.
Autoritäts-URL für Ihre App
Die Anwendungsautoritäten für externe und Mitarbeitermandanten sehen anders aus. Erstellen Sie sie wie unten dargestellt:
//Authority for workforce tenant
authority: process.env.CLOUD_INSTANCE + process.env.TENANT_ID
Verwenden einer benutzerdefinierten URL-Domäne (optional)
Benutzerdefinierte URL-Domänen werden in Mitarbeitermandanten nicht unterstützt.
Hinzufügen von Express-Routen
Die Express-Routen stellen die Endpunkte bereit, die es uns ermöglichen, Vorgänge wie Anmeldung, Abmelden und Anzeigen von ID-Tokenansprüchen auszuführen.
App-Einstiegspunkt
Öffnen Sie in Ihrem Code-Editor die Datei routes/index.js, und fügen Sie den folgenden Code hinzu:
const express = require('express');
const router = express.Router();
router.get('/', function (req, res, next) {
res.render('index', {
title: 'MSAL Node & Express Web App',
isAuthenticated: req.session.isAuthenticated,
username: req.session.account?.username !== '' ? req.session.account?.username : req.session.account?.name,
});
});
module.exports = router;
Die Route / ist der Einstiegspunkt für die Anwendung. Sie rendert die Ansicht "views/index.hbs ", die Sie zuvor in Build-App-UI-Komponenten erstellt haben. isAuthenticated ist eine boolesche Variable, die bestimmt, was in der Ansicht angezeigt wird.
An- und Abmelden
Öffnen Sie in Ihrem Code-Editor Routen/auth.js Datei, und fügen Sie dann den folgenden Code hinzu:
const express = require('express'); const authController = require('../controller/authController'); const router = express.Router(); router.get('/signin', authController.signIn); router.get('/signout', authController.signOut); router.post('/redirect', authController.handleRedirect); module.exports = router;Öffnen Sie in Ihrem Code-Editor die Datei "Controller/authController.js ", und fügen Sie dann den folgenden Code hinzu:
const authProvider = require('../auth/AuthProvider'); exports.signIn = async (req, res, next) => { return authProvider.login(req, res, next); }; exports.handleRedirect = async (req, res, next) => { return authProvider.handleRedirect(req, res, next); } exports.signOut = async (req, res, next) => { return authProvider.logout(req, res, next); };Öffnen Sie in Ihrem Code-Editor die Authentifizierungs-/AuthProvider.js datei, und fügen Sie dann den folgenden Code hinzu:
const msal = require('@azure/msal-node'); const axios = require('axios'); const { msalConfig, TENANT_SUBDOMAIN, REDIRECT_URI, POST_LOGOUT_REDIRECT_URI, GRAPH_ME_ENDPOINT} = require('../authConfig'); class AuthProvider { config; cryptoProvider; constructor(config) { this.config = config; this.cryptoProvider = new msal.CryptoProvider(); } getMsalInstance(msalConfig) { return new msal.ConfidentialClientApplication(msalConfig); } async login(req, res, next, options = {}) { // create a GUID for crsf req.session.csrfToken = this.cryptoProvider.createNewGuid(); /** * The MSAL Node library allows you to pass your custom state as state parameter in the Request object. * The state parameter can also be used to encode information of the app's state before redirect. * You can pass the user's state in the app, such as the page or view they were on, as input to this parameter. */ const state = this.cryptoProvider.base64Encode( JSON.stringify({ csrfToken: req.session.csrfToken, redirectTo: '/', }) ); const authCodeUrlRequestParams = { state: state, /** * By default, MSAL Node will add OIDC scopes to the auth code url request. For more information, visit: * https://docs.microsoft.com/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes */ scopes: [], }; const authCodeRequestParams = { state: state, /** * By default, MSAL Node will add OIDC scopes to the auth code request. For more information, visit: * https://docs.microsoft.com/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes */ scopes: [], }; /** * If the current msal configuration does not have cloudDiscoveryMetadata or authorityMetadata, we will * make a request to the relevant endpoints to retrieve the metadata. This allows MSAL to avoid making * metadata discovery calls, thereby improving performance of token acquisition process. */ if (!this.config.msalConfig.auth.authorityMetadata) { const authorityMetadata = await this.getAuthorityMetadata(); this.config.msalConfig.auth.authorityMetadata = JSON.stringify(authorityMetadata); } const msalInstance = this.getMsalInstance(this.config.msalConfig); // trigger the first leg of auth code flow return this.redirectToAuthCodeUrl( req, res, next, authCodeUrlRequestParams, authCodeRequestParams, msalInstance ); } async handleRedirect(req, res, next) { const authCodeRequest = { ...req.session.authCodeRequest, code: req.body.code, // authZ code codeVerifier: req.session.pkceCodes.verifier, // PKCE Code Verifier }; try { const msalInstance = this.getMsalInstance(this.config.msalConfig); msalInstance.getTokenCache().deserialize(req.session.tokenCache); const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body); req.session.tokenCache = msalInstance.getTokenCache().serialize(); req.session.idToken = tokenResponse.idToken; req.session.account = tokenResponse.account; req.session.isAuthenticated = true; const state = JSON.parse(this.cryptoProvider.base64Decode(req.body.state)); res.redirect(state.redirectTo); } catch (error) { next(error); } } async logout(req, res, next) { /** * Construct a logout URI and redirect the user to end the * session with Microsoft Entra ID. For more information, visit: * https://docs.microsoft.com/azure/active-directory/develop/v2-protocols-oidc#send-a-sign-out-request */ //For external tenant //const logoutUri = `${this.config.msalConfig.auth.authority}${TENANT_SUBDOMAIN}.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=${this.config.postLogoutRedirectUri}`; //For workforce tenant let logoutUri = `${this.config.msalConfig.auth.authority}/oauth2/v2.0/logout?post_logout_redirect_uri=${this.config.postLogoutRedirectUri}`; req.session.destroy(() => { res.redirect(logoutUri); }); } /** * Prepares the auth code request parameters and initiates the first leg of auth code flow * @param req: Express request object * @param res: Express response object * @param next: Express next function * @param authCodeUrlRequestParams: parameters for requesting an auth code url * @param authCodeRequestParams: parameters for requesting tokens using auth code */ async redirectToAuthCodeUrl(req, res, next, authCodeUrlRequestParams, authCodeRequestParams, msalInstance) { // Generate PKCE Codes before starting the authorization flow const { verifier, challenge } = await this.cryptoProvider.generatePkceCodes(); // Set generated PKCE codes and method as session vars req.session.pkceCodes = { challengeMethod: 'S256', verifier: verifier, challenge: challenge, }; /** * By manipulating the request objects below before each request, we can obtain * auth artifacts with desired claims. For more information, visit: * https://azuread.github.io/microsoft-authentication-library-for-js/ref/modules/_azure_msal_node.html#authorizationurlrequest * https://azuread.github.io/microsoft-authentication-library-for-js/ref/modules/_azure_msal_node.html#authorizationcoderequest **/ req.session.authCodeUrlRequest = { ...authCodeUrlRequestParams, redirectUri: this.config.redirectUri, responseMode: 'form_post', // recommended for confidential clients codeChallenge: req.session.pkceCodes.challenge, codeChallengeMethod: req.session.pkceCodes.challengeMethod, }; req.session.authCodeRequest = { ...authCodeRequestParams, redirectUri: this.config.redirectUri, code: '', }; try { const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest); res.redirect(authCodeUrlResponse); } catch (error) { next(error); } } /** * Retrieves oidc metadata from the openid endpoint * @returns */ async getAuthorityMetadata() { // For external tenant //const endpoint = `${this.config.msalConfig.auth.authority}${TENANT_SUBDOMAIN}.onmicrosoft.com/v2.0/.well-known/openid-configuration`; // For workforce tenant const endpoint = `${this.config.msalConfig.auth.authority}/v2.0/.well-known/openid-configuration`; try { const response = await axios.get(endpoint); return await response.data; } catch (error) { console.log(error); } } } const authProvider = new AuthProvider({ msalConfig: msalConfig, redirectUri: REDIRECT_URI, postLogoutRedirectUri: POST_LOGOUT_REDIRECT_URI, }); module.exports = authProvider;Die Routen
/signin,/signoutund/redirectsind in der Datei routes/auth.js definiert, ihre Logik wird jedoch in der Klasse auth/AuthProvider.js implementiert.
Die
login-Methode verarbeitet die Route/signin:Er initiiert den Anmeldefluss, indem der erste Teil des Authentifizierungscodeflusses ausgelöst wird.
Sie initialisiert eine vertrauliche Clientanwendungsinstanz mithilfe des MSAL-Konfigurationsobjekts,
msalConfigdas Sie zuvor erstellt haben.const msalInstance = this.getMsalInstance(this.config.msalConfig);Die
getMsalInstanceMethode wird wie folgt definiert:getMsalInstance(msalConfig) { return new msal.ConfidentialClientApplication(msalConfig); }Die erste Etappe des Authentifizierungscode-Flows generiert eine Autorisierungscodeanforderungs-URL und leitet dann an diese URL um, um den Autorisierungscode abzurufen. Dieses erste Bein wird in der
redirectToAuthCodeUrlMethode implementiert. Beachten Sie, wie wir die MSAL-Methode getAuthCodeUrl verwenden, um die Autorisierungscode-URL zu generieren://... const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest); //...Wir leiten dann zur Autorisierungscode-URL selbst um.
//... res.redirect(authCodeUrlResponse); //...
Die
handleRedirect-Methode verarbeitet die Route/redirect:Sie legen diese URL als Umleitungs-URI für die Web-App im Microsoft Entra Admin Center weiter oben in der Schnellstartanleitung fest: Anmelden von Benutzern in einer Beispielweb-App.
Dieser Endpunkt implementiert die zweite Stufe des Authentifizierungscodes, den der Flow verwendet. Er nutzt den Autorisierungscode, um mithilfe der Methode acquireTokenByCode ein ID-Token von MSAL anzufordern.
//... const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body); //...Nachdem Sie eine Antwort erhalten haben, können Sie eine Express-Sitzung erstellen und alle gewünschten Informationen darin speichern. Sie müssen
isAuthenticatedeinschließen und auftruefestlegen://... req.session.idToken = tokenResponse.idToken; req.session.account = tokenResponse.account; req.session.isAuthenticated = true; //...
Die
logout-Methode verarbeitet die Route/signout:async logout(req, res, next) { /** * Construct a logout URI and redirect the user to end the * session with Azure AD. For more information, visit: * https://docs.microsoft.com/azure/active-directory/develop/v2-protocols-oidc#send-a-sign-out-request */ const logoutUri = `${this.config.msalConfig.auth.authority}${TENANT_SUBDOMAIN}.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=${this.config.postLogoutRedirectUri}`; req.session.destroy(() => { res.redirect(logoutUri); }); }Sie initiiert die Abmeldungsanforderung.
Wenn Sie den Benutzer von der Anwendung abmelden möchten, reicht es nicht aus, nur die Benutzersitzung zu beenden. Sie müssen den Benutzer an den LogoutUri umleiten. Ansonsten kann sich der Benutzer möglicherweise erneut bei Ihrer Anwendung authentifizieren, ohne seine Anmeldeinformationen erneut einzugeben. Wenn der Name Ihres Mandanten "contoso" lautet, sieht der logoutUri ähnlich aus wie
https://contoso.ciamlogin.com/contoso.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000.
Abmelde-URI und Autoritätsmetadatenendpunkt für Ihre App
Der Abmelde-URI logoutUri der App und der Autoritätsmetadatenendpunkt endpoint für externe und Mitarbeitermandanten sehen anders aus. Erstellen Sie sie wie unten dargestellt:
//Logout URI for workforce tenant
const logoutUri = `${this.config.msalConfig.auth.authority}/oauth2/v2.0/logout?post_logout_redirect_uri=${this.config.postLogoutRedirectUri}`;
//authority metadata endpoint for workforce tenant
const endpoint = `${this.config.msalConfig.auth.authority}/v2.0/.well-known/openid-configuration`;
ID-Token-Ansprüche anzeigen
Öffnen Sie in Ihrem Code-Editor die Datei routes/users.js, und fügen Sie den folgenden Code hinzu:
const express = require('express');
const router = express.Router();
// custom middleware to check auth state
function isAuthenticated(req, res, next) {
if (!req.session.isAuthenticated) {
return res.redirect('/auth/signin'); // redirect to sign-in route
}
next();
};
router.get('/id',
isAuthenticated, // check if user is authenticated
async function (req, res, next) {
res.render('id', { idTokenClaims: req.session.account.idTokenClaims });
}
);
module.exports = router;
Wenn der Benutzer authentifiziert ist, zeigt die /id Route ID-Tokenansprüche mithilfe der Ansicht "views/id.hbs " an. Sie haben diese Ansicht weiter oben unter Erstellen von Komponenten der App-Benutzeroberfläche hinzugefügt.
So extrahieren Sie einen bestimmten ID-Tokenanspruch, z. B. den angegebenen Namen:
const givenName = req.session.account.idTokenClaims.given_name
Fertigstellen Ihrer Web-App
Öffnen Sie in Ihrem Code-Editor app.js Datei, und fügen Sie den Code aus app.js hinzu.
Öffnen Sie in Ihrem Code-Editor server.js Datei, und fügen Sie den Code aus server.js hinzu.
Öffnen Sie in Ihrem Code-Editor package.json Datei, und aktualisieren Sie die
scriptsEigenschaft auf:"scripts": { "start": "node server.js" }
Ausführen und Testen der Node/Express.js Web-App
An diesem Punkt können Sie Ihre Knoten-Web-App testen.
Verwenden Sie die Schritte unter Erstellen eines neuen Benutzers, um einen Testbenutzer im Mitarbeitermandanten zu erstellen. Wenn Sie keinen Zugriff auf den Mandanten haben, bitten Sie Ihren Mandantenadministrator, den Benutzer für Sie zu erstellen.
Führen Sie zum Starten des Servers die folgenden Befehle aus dem Projektverzeichnis aus:
npm startÖffnen Sie Ihren Browser, und wechseln Sie dann zu
http://localhost:3000. Die daraufhin angezeigte Seite sollte dem folgenden Screenshot ähneln:
Wählen Sie Anmelden aus, um den Anmeldeprozess zu starten. Wenn Sie sich zum ersten Mal anmelden, werden Sie aufgefordert, Ihre Zustimmung zu geben, damit sich die Anwendung anmelden und auf Ihr Profil zugreifen kann, wie im folgenden Screenshot gezeigt:
Nachdem Sie erfolgreich angemeldet sind, werden Sie wieder zur Startseite der Anwendung umgeleitet.
