Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Van toepassing op: Workforce-huurders
Externe huurders (meer informatie)
In deze zelfstudie voegt u aanmeldings- en afmeldingslogica toe aan uw Node/Express-web-app. Met deze code kunt u gebruikers aanmelden bij uw klantgerichte app vanuit een externe tenant of werknemers in een personeelstenant.
Deze zelfstudie is deel 2 van de driedelige reeks zelfstudies.
In deze handleiding leert u:
- Aanmeldings- en afmeldingslogica toevoegen
- ID-tokenclaims bekijken
- Voer de app uit en test de aanmeldings- en afmeldingservaring.
Voorwaarden
- Voltooi de stappen in Zelfstudie: Een Node.js-web-app instellen om gebruikers aan te melden met behulp van het Microsoft Identity Platform.
MSAL-configuratieobject maken
Open authConfig.js bestand in de code-editor en voeg de volgende code toe:
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
};
Het msalConfig
-object bevat een set configuratieopties die u gebruikt om het gedrag van uw verificatiestromen aan te passen.
Vervang het volgende in het authConfig.js-bestand:
Enter_the_Application_Id_Here
met de toepassings-id (client) van de app die u eerder hebt geregistreerd.Enter_the_Tenant_Subdomain_Here
en vervang deze door het subdomein van de externe directory (huurder). Als uw primaire tenantdomein bijvoorbeeld iscontoso.onmicrosoft.com
, gebruikt ucontoso
. Als u uw tenantnaam niet hebt, leert u hoe u uw tenantgegevens kunt lezen. Deze waarde is alleen vereist voor externe tenant-.Enter_the_Client_Secret_Here
met de waarde van het applicatiegeheim die u eerder gekopieerd hebt.Enter_the_Graph_Endpoint_Here
met de Microsoft Graph API-cloudinstantie die door uw app wordt aangeroepen. Gebruik de waarde https://graph.microsoft.com/ (inclusief de afsluitende schuine streep)
Als u het bestand .env gebruikt om uw configuratiegegevens op te slaan:
Open in de code-editor .env-bestand en voeg vervolgens de volgende code toe.
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 text
Vervang de plaatsaanduiding:
-
Enter_the_Application_Id_Here
,Enter_the_Tenant_Subdomain_Here
enEnter_the_Client_Secret_Here
zoals eerder uitgelegd. -
Enter_the_Cloud_Instance_Id_Here
bij de Azure-cloudinstantie waarin uw toepassing is geregistreerd. Gebruik https://login.microsoftonline.com/ als waarde (inclusief de afsluitende schuine streep naar rechts). Deze waarde is alleen vereist voor werknemerstenant. -
Enter_the_Tenant_ID_here
met de tenant-id van het personeel of het primaire domein, zoals aaaabbbb-0000-cccc-1111-dddd2222eeee of contoso.microsoft.com. Deze waarde is alleen vereist voor werknemerstenant.
-
U exporteert msalConfig
, REDIRECT_URI
, TENANT_SUBDOMAIN
, GRAPH_ME_ENDPOINT
en POST_LOGOUT_REDIRECT_URI
variabelen in het authConfig.js bestand om ze toegankelijk te maken in andere bestanden.
URL van de authoriteit voor uw app
De toepassingsautoriteiten voor externe tenants en werknemers zien er anders uit. Bouw ze zoals hieronder wordt weergegeven:
//Authority for workforce tenant
authority: process.env.CLOUD_INSTANCE + process.env.TENANT_ID
Aangepast URL-domein gebruiken (optioneel)
Aangepaste URL-domeinen worden niet ondersteund in werkplaats-tenants.
Expressroutes toevoegen
De Express-routes bieden de eindpunten waarmee we bewerkingen kunnen uitvoeren, zoals aanmelden, afmelden en id-tokenclaims weergeven.
App-toegangspunt
Open in de code-editor routes/index.js bestand en voeg vervolgens de volgende code toe:
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;
De /
route is het toegangspunt voor de toepassing. Hiermee wordt de views/index.hbs weergave getoond die u eerder hebt gemaakt in het bouwen van app-UI-onderdelen.
isAuthenticated
is een Booleaanse variabele die bepaalt wat u in de weergave ziet.
Aanmelden en afmelden
Open in de code-editor routes/auth.js bestand en voeg vervolgens de volgende code toe:
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;
Open in de code-editor controller-/authController.js-bestand en voeg vervolgens de volgende code toe:
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); };
Open in de code-editor auth/AuthProvider.js-bestand en voeg de volgende code toe:
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;
De routes
/signin
,/signout
en/redirect
worden gedefinieerd in het routes-/auth.js-bestand, maar u implementeert de logica in de klasse auth/AuthProvider.js.
Methode
login
beheert de route/signin
:De aanmeldingsstroom wordt gestart door het eerste deel van de verificatiecodestroom te activeren.
Hiermee wordt een vertrouwelijke clienttoepassing geïnitialiseerd exemplaar met behulp van msal-configuratieobject,
msalConfig
, dat u eerder hebt gemaakt.const msalInstance = this.getMsalInstance(this.config.msalConfig);
De methode
getMsalInstance
wordt gedefinieerd als:getMsalInstance(msalConfig) { return new msal.ConfidentialClientApplication(msalConfig); }
Het eerste deel van de verificatiecodestroom genereert een aanvraag-URL voor autorisatiecode en leidt vervolgens om naar die URL om de autorisatiecode te verkrijgen. Deze eerste etappe wordt geïmplementeerd in de methode
redirectToAuthCodeUrl
. U ziet hoe we MSALs getAuthCodeUrl methode gebruiken om autorisatiecode-URL te genereren://... const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest); //...
Vervolgens wordt u omgeleid naar de URL van de autorisatiecode zelf.
//... res.redirect(authCodeUrlResponse); //...
Methode
handleRedirect
beheert de route/redirect
:U stelt deze URL in als omleidings-URI voor de web-app in het Microsoft Entra-beheercentrum eerder in quickstart: Gebruikers aanmelden in een voorbeeldweb-app.
Met dit eindpunt wordt het tweede deel van de verificatiecodestroom geïmplementeerd. De autorisatiecode wordt gebruikt om een id-token aan te vragen met behulp van de acquireTokenByCode methode van MSAL.
//... const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body); //...
Nadat u een antwoord hebt ontvangen, kunt u een Express-sessie maken en de gewenste informatie hierin opslaan. U moet
isAuthenticated
opnemen en deze instellen optrue
://... req.session.idToken = tokenResponse.idToken; req.session.account = tokenResponse.account; req.session.isAuthenticated = true; //...
Methode
logout
beheert de 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); }); }
Er wordt een afmeldingsaanvraag gestart.
Wanneer u de gebruiker wilt afmelden bij de toepassing, is het niet voldoende om de sessie van de gebruiker te beëindigen. U moet de gebruiker omleiden naar de logoutUri. Anders kan de gebruiker zich mogelijk opnieuw aanmelden bij uw applicaties zonder hun inloggegevens opnieuw in te voeren. Als de naam van uw tenant is contoso, ziet de logoutUri er ongeveer uit als
https://contoso.ciamlogin.com/contoso.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000
.
Uitlog-URI en authority-metadata-eindpunt voor je app
De afmeldings-URI van de app, logoutUri
, en het metagegevenseindpunt van de instantie, endpoint
, zien er voor externe en werknemershuurders anders uit. Bouw ze zoals hieronder wordt weergegeven:
//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-tokenclaims weergeven
Open in de code-editor routes/users.js bestand en voeg vervolgens de volgende code toe:
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;
Als de gebruiker is geverifieerd, geeft de /id
route id-tokenclaims weer met behulp van de views/id.hbs weergave. U hebt deze weergave eerder toegevoegd in Bouw UI-componenten van de app.
Een specifieke id-tokenclaim extraheren, zoals voornaam:
const givenName = req.session.account.idTokenClaims.given_name
Uw web-app voltooien
Open in de code-editor app.js bestand en voeg de code uit app.js toe.
Open in de code-editor server.js bestand en voeg de code uit server.js toe.
Open package.json bestand in de code-editor en werk de eigenschap
scripts
bij naar:"scripts": { "start": "node server.js" }
De Node/Express.js-web-app uitvoeren en testen
Op dit moment kunt u uw knooppuntweb-app testen.
Gebruik de stappen in Een nieuwe gebruiker aanmaken om een testgebruiker aan te maken in de personeelsomgeving. Als u geen toegang tot de tenant hebt, vraagt u de tenantbeheerder om de gebruiker voor u te maken.
Voer de volgende opdrachten uit vanuit de projectmap om de server te starten:
npm start
Open uw browser en ga vervolgens naar
http://localhost:3000
. De pagina ziet er ongeveer als volgt uit:Klik op Aanmelden om het aanmeldproces te starten. De eerste keer dat u zich aanmeldt, wordt u gevraagd uw toestemming te geven zodat de toepassing u kan aanmelden en toegang krijgt tot uw profiel, zoals wordt weergegeven in de volgende schermafbeelding:
Nadat u bent aangemeld, wordt u teruggeleid naar de startpagina van de toepassing.