Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Platí pro:
Tenanti pracovních sil
Externí tenanti (další informace)
V tomto kurzu přidáte logiku přihlášení a odhlášení do webové aplikace Node/Express. Tento kód umožňuje přihlašovat uživatele do vaší aplikace pro zákazníky, a to buď v externím tenantovi, nebo v pracovním tenantovi zaměstnanců.
Tento kurz je 2. částí třídílné série kurzů.
V tomto kurzu se naučíte:
- Přidání logiky přihlašování a odhlášení
- Zobrazení deklarací ID tokenu
- Spusťte aplikaci a otestujte prostředí přihlašování a odhlášení.
Požadavky
- Dokončete kroky v tutoriálu: Nastavte Node.js webovou aplikaci pro přihlášení uživatelů pomocí platformy Microsoft identity.
Vytvoření objektu konfigurace MSAL
V editoru kódu otevřete souborauthConfig.js a přidejte následující kód:
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
};
Objekt msalConfig obsahuje sadu možností konfigurace, které používáte k přizpůsobení chování toků ověřování.
V souboruauthConfig.js nahraďte:
Enter_the_Application_Id_Heres ID aplikace (klienta), kterou jste zaregistrovali dříve.Enter_the_Tenant_Subdomain_Herea nahraďte ji subdoménou externího adresáře (tenanta). Pokud je například primární doména vašeho tenantacontoso.onmicrosoft.com, použijtecontoso. Jestliže nemáte jméno tenanta, zjistěte, jak si přečíst informace o svém tenantovi. Tato hodnota se vyžaduje jenom pro externího tenanta.Enter_the_Client_Secret_Heres hodnotou tajného klíče aplikace, kterou jste dříve zkopírovali.Enter_the_Graph_Endpoint_Heres cloudovou instancí rozhraní Microsoft Graph API, kterou bude vaše aplikace volat. Použijte hodnotuhttps://graph.microsoft.com/(včetně koncového lomítka).
Pokud k uložení konfiguračních informací použijete soubor .env :
V editoru kódu otevřete soubor .env a přidejte následující kód.
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 textZástupný symbol nahraďte:
-
Enter_the_Application_Id_HereEnter_the_Tenant_Subdomain_HereaEnter_the_Client_Secret_Herejak bylo vysvětleno dříve. -
Enter_the_Cloud_Instance_Id_Heres instancí cloudu Azure, ve které je vaše aplikace zaregistrovaná. Použijtehttps://login.microsoftonline.com/jako hodnotu (včetně koncového lomítka). Tato hodnota se vyžaduje jenom pro tenanta pracovních sil. -
Enter_the_Tenant_ID_heres ID tenanta pracovní síly nebo primární doménou, jako například aaaabbbb-0000-cccc-1111-dddd2222eeee nebo contoso.microsoft.com. Tato hodnota se vyžaduje jenom pro tenanta pracovních sil.
-
Exportujete msalConfig, REDIRECT_URI, TENANT_SUBDOMAINGRAPH_ME_ENDPOINT a POST_LOGOUT_REDIRECT_URI proměnné v souboruauthConfig.js, aby byly přístupné v jiných souborech.
Adresa URL autority pro vaši aplikaci
Orgány pro aplikace pro externí nájemce a nájemce z řad pracovních sil se liší. Sestavte je, jak je znázorněno níže:
//Authority for workforce tenant
authority: process.env.CLOUD_INSTANCE + process.env.TENANT_ID
Použití vlastní domény URL (volitelné)
Vlastní domény URL nejsou podporovány v tenantech pracovních sil.
Přidání expresních tras
Trasy Express poskytují koncové body, které nám umožňují provádět operace, jako je přihlášení, odhlášení a zobrazení deklarací identity tokenu ID.
Vstupní bod aplikace
V editoru kódu otevřete trasy/index.js soubor a přidejte následující kód:
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;
Trasa / je vstupním bodem aplikace. Zobrazí pohled views/index.hbs, který jste vytvořili dříve v části Sestavení součástí uživatelského rozhraní aplikace.
isAuthenticated je logická proměnná, která určuje, co vidíte v zobrazení.
Přihlášení a odhlášení
V editoru kódu otevřete trasy/auth.js soubor a přidejte následující kód:
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;V editoru kódu otevřete soubor kontroleru neboauthController.js a přidejte následující kód:
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); };V editoru kódu otevřete soubor ověřování neboAuthProvider.js a přidejte následující kód:
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;Trasy
/signin,/signouta/redirectjsou definovány v souboru routes/auth.js, ale jejich logiku implementujete ve třídě auth/AuthProvider.js.
Metoda
loginzpracovává trasu/signin:Spustí tok přihlášení tím, že aktivuje první část toku ověřovacího kódu.
Inicializuje důvěrnou instanci klientské aplikace pomocí objektu konfigurace MSAL ,
msalConfigkterý jste vytvořili dříve.const msalInstance = this.getMsalInstance(this.config.msalConfig);Metoda
getMsalInstanceje definována takto:getMsalInstance(msalConfig) { return new msal.ConfidentialClientApplication(msalConfig); }První část toku ověřovacího kódu vygeneruje adresu URL požadavku na autorizační kód a pak přesměruje na danou adresu URL a získá autorizační kód. Tato první fáze je implementována v metodě
redirectToAuthCodeUrl. Všimněte si, že k vygenerování adresy URL autorizačního kódu používáme metodu MSALs getAuthCodeUrl ://... const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest); //...Pak přesměrujeme na samotnou adresu URL autorizačního kódu.
//... res.redirect(authCodeUrlResponse); //...
Metoda
handleRedirectzpracovává trasu/redirect:Tuto adresu URL jste dříve nastavili jako identifikátor URI přesměrování pro webovou aplikaci v Centru pro správu Microsoft Entra v Rychlý start: Přihlášení uživatelů v ukázkové webové aplikaci.
Tento koncový bod implementuje druhou fázi použití toku ověřovacího kódu. Autorizační kód používá k vyžádání tokenu ID pomocí metody acquireTokenByCode knihovny MSAL.
//... const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body); //...Jakmile obdržíte odpověď, můžete vytvořit relaci Expressu a uložit do ní libovolné informace. Musíte zahrnout
isAuthenticateda nastavit ho natrue://... req.session.idToken = tokenResponse.idToken; req.session.account = tokenResponse.account; req.session.isAuthenticated = true; //...
Metoda
logoutzpracovává trasu/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); }); }Zahájí žádost o odhlášení.
Pokud chcete uživatele odhlásit z aplikace, nestačí ukončit relaci uživatele. Uživatele musíte přesměrovat na logoutUri. V opačném případě může být uživatel schopen znovu provést ověření vašich aplikací bez opětovného zadání přihlašovacích údajů. Pokud je název vašeho tenanta contoso, vypadá logoutUri podobně jako
https://contoso.ciamlogin.com/contoso.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000.
Výstupní URI a koncový bod metadat autority pro vaši aplikaci
Identifikátor URI logoutUri odhlášení aplikace a koncový bod endpoint metadat autority pro externí a podnikové tenanty vypadají jinak. Sestavte je, jak je znázorněno níže:
//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`;
Zobrazení deklarací ID tokenu
V editoru kódu otevřete trasy/users.js soubor a přidejte následující kód:
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;
Pokud je uživatel ověřený, /id cesta zobrazí deklarace ID tokenu pomocí zobrazení views/id.hbs. Toto zobrazení jste přidali dříve v vytváření komponent uživatelského rozhraní aplikace.
Pokud chcete extrahovat konkrétní deklaraci identity tokenu ID, například název:
const givenName = req.session.account.idTokenClaims.given_name
Dokončení webové aplikace
V editoru kódu otevřete souborapp.js a pak do něj přidejte kód z app.js .
V editoru kódu otevřete souborserver.js a pak do něj přidejte kód z server.js .
V editoru kódu otevřete souborpackage.json a aktualizujte
scriptsvlastnost na:"scripts": { "start": "node server.js" }
Spuštění a otestování webové aplikace Node/Express.js
V tuto chvíli můžete webovou aplikaci node otestovat.
Pomocí kroků v části Vytvoření nového uživatele vytvořte testovacího uživatele v tenantovi pracovních sil. Pokud nemáte přístup k tenantovi, požádejte správce tenanta, aby za vás vytvořil uživatele.
Pokud chcete spustit server, spusťte v adresáři projektu následující příkazy:
npm startOtevřete prohlížeč a přejděte na
http://localhost:3000. Měla by se zobrazit stránka podobná následujícímu snímku obrazovky:
Výběrem možnosti Přihlásit se spusťte proces přihlášení. Při prvním přihlášení se zobrazí výzva k zadání souhlasu, abyste aplikaci povolili přihlášení a přístup k vašemu profilu, jak je znázorněno na následujícím snímku obrazovky:
Po úspěšném přihlášení budete přesměrováni zpět na domovskou stránku aplikace.