Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Important
À compter du 1er mai 2025, Azure AD B2C ne sera plus disponible pour les nouveaux clients. Pour plus d’informations, consultez notre FAQ.
Dans cet article, vous allez apprendre à créer votre application web qui appelle votre API web. L’API web doit être protégée par Azure Active Directory B2C (Azure AD B2C). Pour autoriser l’accès à l’API web, vous répondez aux demandes qui incluent un jeton d’accès valide émis par Azure AD B2C.
Conditions préalables
Avant de lire et de suivre les étapes, configurez l'authentification dans un exemple d'API web Node.js à l'aide d'Azure AD B2C. Suivez ensuite les étapes décrites dans cet article pour remplacer l’exemple d’application web et l’API web par votre propre API web.
Visual Studio Code ou un autre éditeur de code
Étape 1 : Créer une API web protégée
Suivez ces étapes pour créer votre API web Node.js.
Étape 1.1 : Créer le projet
Utilisez Express pour Node.js pour créer une API web. Pour créer une API web, procédez comme suit :
- Créez un dossier appelé
TodoList
. - Sous le
TodoList
dossier, créez un fichier nomméindex.js
. - Dans un interpréteur de commandes, exécutez
npm init -y
. Cette commande crée un fichierpackage.json
par défaut pour votre projet Node.js. - Dans l’interpréteur de commandes, exécutez
npm install express
. Cette commande installe l’infrastructure Express.
Étape 1.2 : Installer les dépendances
Ajoutez la bibliothèque d’authentification à votre projet d’API web. La bibliothèque d’authentification analyse l’en-tête d’authentification HTTP, valide le jeton et extrait les revendications. Pour plus d’informations, consultez la documentation de la bibliothèque.
Pour ajouter la bibliothèque d’authentification, installez les packages en exécutant la commande suivante :
npm install passport
npm install passport-azure-ad
npm install morgan
Le package morgan est un middleware de journalisation des requêtes HTTP pour Node.js.
Étape 1.3 : Écrire le code du serveur d’API web
Dans le index.js
fichier, ajoutez le code suivant :
const express = require('express');
const morgan = require('morgan');
const passport = require('passport');
const config = require('./config.json');
const todolist = require('./todolist');
const cors = require('cors');
//<ms_docref_import_azuread_lib>
const BearerStrategy = require('passport-azure-ad').BearerStrategy;
//</ms_docref_import_azuread_lib>
global.global_todos = [];
//<ms_docref_azureadb2c_options>
const options = {
identityMetadata: `https://${config.credentials.tenantName}.b2clogin.com/${config.credentials.tenantName}.onmicrosoft.com/${config.policies.policyName}/${config.metadata.version}/${config.metadata.discovery}`,
clientID: config.credentials.clientID,
audience: config.credentials.clientID,
policyName: config.policies.policyName,
isB2C: config.settings.isB2C,
validateIssuer: config.settings.validateIssuer,
loggingLevel: config.settings.loggingLevel,
passReqToCallback: config.settings.passReqToCallback
}
//</ms_docref_azureadb2c_options>
//<ms_docref_init_azuread_lib>
const bearerStrategy = new BearerStrategy(options, (token, done) => {
// Send user info using the second argument
done(null, { }, token);
}
);
//</ms_docref_init_azuread_lib>
const app = express();
app.use(express.json());
//enable CORS (for testing only -remove in production/deployment)
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Authorization, Origin, X-Requested-With, Content-Type, Accept');
next();
});
app.use(morgan('dev'));
app.use(passport.initialize());
passport.use(bearerStrategy);
// To do list endpoints
app.use('/api/todolist', todolist);
//<ms_docref_protected_api_endpoint>
// API endpoint, one must present a bearer accessToken to access this endpoint
app.get('/hello',
passport.authenticate('oauth-bearer', {session: false}),
(req, res) => {
console.log('Validated claims: ', req.authInfo);
// Service relies on the name claim.
res.status(200).json({'name': req.authInfo['name']});
}
);
//</ms_docref_protected_api_endpoint>
//<ms_docref_anonymous_api_endpoint>
// API anonymous endpoint, returns a date to the caller.
app.get('/public', (req, res) => res.send( {'date': new Date() } ));
//</ms_docref_anonymous_api_endpoint>
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log('Listening on port ' + port);
});
Notez les extraits de code suivants dans le index.js
fichier :
Importe la bibliothèque de Microsoft Entra de passeport
const BearerStrategy = require('passport-azure-ad').BearerStrategy;
Définit les options Azure AD B2C
const options = { identityMetadata: `https://${config.credentials.tenantName}.b2clogin.com/${config.credentials.tenantName}.onmicrosoft.com/${config.policies.policyName}/${config.metadata.version}/${config.metadata.discovery}`, clientID: config.credentials.clientID, audience: config.credentials.clientID, policyName: config.policies.policyName, isB2C: config.settings.isB2C, validateIssuer: config.settings.validateIssuer, loggingLevel: config.settings.loggingLevel, passReqToCallback: config.settings.passReqToCallback }
Instancie la bibliothèque Microsoft Entra de passeport avec les options Azure AD B2C
const bearerStrategy = new BearerStrategy(options, (token, done) => { // Send user info using the second argument done(null, { }, token); } );
Point de terminaison d’API protégé. Il traite les demandes qui incluent un jeton d’accès émis par Azure AD B2C valide. il retourne la valeur de la revendication
name
dans le jeton d’accès.// API endpoint, one must present a bearer accessToken to access this endpoint app.get('/hello', passport.authenticate('oauth-bearer', {session: false}), (req, res) => { console.log('Validated claims: ', req.authInfo); // Service relies on the name claim. res.status(200).json({'name': req.authInfo['name']}); } );
Point de terminaison d’API anonyme. L’application web peut l’appeler sans présenter de jeton d’accès. Utilisez-le pour déboguer votre API web avec des appels anonymes.
// API anonymous endpoint, returns a date to the caller. app.get('/public', (req, res) => res.send( {'date': new Date() } ));
Étape 1.4 : Configurer l’API web
Ajoutez des configurations à un fichier de configuration. Le fichier contient des informations sur votre fournisseur d’identité Azure AD B2C. L'application API web utilise ces informations pour valider le jeton d'accès que l'application web transmet comme jeton porteur.
Sous le dossier racine du projet, créez un
config.json
fichier, puis ajoutez-le à l’objet JSON suivant :{ "credentials": { "tenantName": "fabrikamb2c", "clientID": "Enter_the_Application_Id_Here" }, "policies": { "policyName": "B2C_1_susi" }, "resource": { "scope": ["tasks.read"] }, "metadata": { "authority": "login.microsoftonline.com", "discovery": ".well-known/openid-configuration", "version": "v2.0" }, "settings": { "isB2C": true, "validateIssuer": true, "passReqToCallback": false, "loggingLevel": "info" } }
Dans le
config.json
fichier, mettez à jour les propriétés suivantes :
Section | Clé | Valeur |
---|---|---|
informations d’identification | nom du locataire | Première partie de votre nom de client Azure AD B2C (par exemple, fabrikamb2c ). |
informations d’identification | identifiant du client | ID d’application de l’API web. Pour savoir comment obtenir votre ID d’inscription d’application d’API web, consultez Conditions préalables. |
politiques | nom_stratégie | Les parcours utilisateur ou une stratégie personnalisée. Pour savoir comment obtenir votre flux d’utilisateur ou votre stratégie, consultez Conditions préalables. |
ressource | portée | Étendues de l’inscription de votre application API web (par exemple, [tasks.read] ). Pour savoir comment obtenir l’étendue de votre API web, consultez Conditions préalables. |
Étape 2 : Créer l’application web Node web
Procédez comme suit pour créer l’application web Node. Cette application web authentifie un utilisateur pour acquérir un jeton d’accès utilisé pour appeler l’API web Node que vous avez créée à l’étape 1 :
Étape 2.1 : Créer le projet de nœud
Créez un dossier pour contenir votre application Node.js, comme call-protected-api
.
Dans votre terminal, remplacez le répertoire par votre dossier d’application de nœud, par
cd call-protected-api
exemple, et exécuteznpm init -y
. Cette commande crée un fichier package.json par défaut pour votre projet Node.js.Dans votre terminal, exécutez
npm install express
. Cette commande installe l’infrastructure Express.Créez d’autres dossiers et fichiers pour obtenir la structure de projet suivante :
call-protected-api/ ├── index.js └── package.json └── .env └── views/ └── layouts/ └── main.hbs └── signin.hbs └── api.hbs
Le
views
dossier contient des fichiers handlebars pour l’interface utilisateur de l’application web.
Étape 2.2 : Installer les dépendances
Dans votre terminal, installez les paquets dotenv
, express-handlebars
, express-session
et @azure/msal-node
en exécutant les commandes suivantes :
npm install dotenv
npm install express-handlebars
npm install express
npm install axios
npm install express-session
npm install @azure/msal-node
Étape 2.3 : Créer des composants d’interface utilisateur d’application web
Dans le
main.hbs
fichier, ajoutez le code suivant :<!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"> <title>Azure AD B2C | Enable authenticate on web API using MSAL for B2C</title> <!-- adding Bootstrap 4 for UI components --> <!-- CSS only --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> <link rel="SHORTCUT ICON" href="https://c.s-microsoft.com/favicon.ico?v2" type="image/x-icon"> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-primary"> <a class="navbar-brand" href="/">Microsoft Identity Platform</a> {{#if showSignInButton}} <div class="ml-auto"> <a type="button" id="SignIn" class="btn btn-success" href="/signin" aria-haspopup="true" aria-expanded="false"> Sign in to call PROTECTED API </a> <a type="button" id="SignIn" class="btn btn-warning" href="/api" aria-haspopup="true" aria-expanded="false"> Or call the ANONYMOUS API </a> </div> {{else}} <p class="navbar-brand d-flex ms-auto">Hi {{givenName}}</p> <a class="navbar-brand d-flex ms-auto" href="/signout">Sign out</a> {{/if}} </nav> <br> <h5 class="card-header text-center">MSAL Node Confidential Client application with Auth Code Flow</h5> <br> <div class="row" style="margin:auto" > {{{body}}} </div> <br> <br> </body> </html>
Le
main.hbs
fichier se trouve dans lelayout
dossier et doit contenir tout code HTML requis dans l’ensemble de votre application. Il implémente l’interface utilisateur générée avec l’infrastructure CSS Bootstrap 5. Toute interface utilisateur qui passe de la page à la page, telle quesignin.hbs
, est placée dans l’espace réservé affiché comme{{{body}}}
.Dans le
signin.hbs
fichier, ajoutez le code suivant :<div class="col-md-3" style="margin:auto"> <div class="card text-center"> <div class="card-body"> {{#if showSignInButton}} {{else}} <h5 class="card-title">You have signed in</h5> <a type="button" id="Call-api" class="btn btn-success" href="/api" aria-haspopup="true" aria-expanded="false"> Call the PROTECTED API </a> {{/if}} </div> </div> </div> </div>
Dans le
api.hbs
fichier, ajoutez le code suivant :<div class="col-md-3" style="margin:auto"> <div class="card text-center bg-{{bg_color}}"> <div class="card-body"> <h5 class="card-title">{{data}}</h5> </div> </div> </div>
Cette page affiche la réponse de l’API. L’attribut
bg-{{bg_color}}
de classe dans la carte bootstrap permet à l’interface utilisateur d’afficher une couleur d’arrière-plan différente pour les différents points de terminaison d’API.
Étape 2.4 : Code complet du serveur d’applications web
Dans le fichier
.env
, ajoutez le code suivant, qui inclut le port http du serveur, les informations d’enregistrement de l’application, ainsi que les détails des flux utilisateur/de la politique de connexion et d'inscription.SERVER_PORT=3000 #web apps client ID APP_CLIENT_ID=<You app client ID here> #session secret SESSION_SECRET=sessionSecretHere #web app client secret APP_CLIENT_SECRET=<Your app client secret here> #tenant name TENANT_NAME=<your-tenant-name> #B2C sign up and sign in user flow/policy name and authority SIGN_UP_SIGN_IN_POLICY_AUTHORITY=https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<sign-in-sign-up-user-flow-name> AUTHORITY_DOMAIN=https://<your-tenant-name>.b2clogin.com #client redorect url APP_REDIRECT_URI=http://localhost:3000/redirect LOGOUT_ENDPOINT=https://<your-tenant-name>.b2clogin.com/<your-tenant-name>.onmicrosoft.com/<sign-in-sign-up-user-flow-name>/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000
Modifier les valeurs dans les
.env
fichiers, comme expliqué dans Configurer l’exemple d’application webDans votre
index.js
fichier, ajoutez le code suivant :/* * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ require('dotenv').config(); const express = require('express'); const session = require('express-session'); const {engine} = require('express-handlebars'); const msal = require('@azure/msal-node'); //Use axios to make http calls const axios = require('axios'); //<ms_docref_configure_msal> /** * Confidential Client Application Configuration */ const confidentialClientConfig = { auth: { clientId: process.env.APP_CLIENT_ID, authority: process.env.SIGN_UP_SIGN_IN_POLICY_AUTHORITY, clientSecret: process.env.APP_CLIENT_SECRET, knownAuthorities: [process.env.AUTHORITY_DOMAIN], //This must be an array redirectUri: process.env.APP_REDIRECT_URI, validateAuthority: false }, system: { loggerOptions: { loggerCallback(loglevel, message, containsPii) { console.log(message); }, piiLoggingEnabled: false, logLevel: msal.LogLevel.Verbose, } } }; // Initialize MSAL Node const confidentialClientApplication = new msal.ConfidentialClientApplication(confidentialClientConfig); //</ms_docref_configure_msal> // Current web API coordinates were pre-registered in a B2C tenant. //<ms_docref_api_config> const apiConfig = { webApiScopes: [`https://${process.env.TENANT_NAME}.onmicrosoft.com/tasks-api/tasks.read`], anonymousUri: 'http://localhost:5000/public', protectedUri: 'http://localhost:5000/hello' }; //</ms_docref_api_config> /** * The MSAL.js library allows you to pass your custom state as state parameter in the Request object * By default, MSAL.js passes a randomly generated unique state parameter value in the authentication requests. * 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. * For more information, visit: https://docs.microsoft.com/azure/active-directory/develop/msal-js-pass-custom-state-authentication-request */ const APP_STATES = { LOGIN: 'login', CALL_API:'call_api' } /** * Request Configuration * We manipulate these two request objects below * to acquire a token with the appropriate claims. */ const authCodeRequest = { redirectUri: confidentialClientConfig.auth.redirectUri, }; const tokenRequest = { redirectUri: confidentialClientConfig.auth.redirectUri, }; /** * Using express-session middleware. Be sure to familiarize yourself with available options * and set them as desired. Visit: https://www.npmjs.com/package/express-session */ const sessionConfig = { secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false, cookie: { secure: false, // set this to true on production } } //Create an express instance const app = express(); //Set handlebars as your view engine app.engine('.hbs', engine({extname: '.hbs'})); app.set('view engine', '.hbs'); app.set("views", "./views"); app.use(session(sessionConfig)); /** * This method is used to generate an auth code request * @param {string} authority: the authority to request the auth code from * @param {array} scopes: scopes to request the auth code for * @param {string} state: state of the application, tag a request * @param {Object} res: express middleware response object */ const getAuthCode = (authority, scopes, state, res) => { // prepare the request console.log("Fetching Authorization code") authCodeRequest.authority = authority; authCodeRequest.scopes = scopes; authCodeRequest.state = state; //Each time you fetch Authorization code, update the authority in the tokenRequest configuration tokenRequest.authority = authority; // request an authorization code to exchange for a token return confidentialClientApplication.getAuthCodeUrl(authCodeRequest) .then((response) => { console.log("\nAuthCodeURL: \n" + response); //redirect to the auth code URL/send code to res.redirect(response); }) .catch((error) => { res.status(500).send(error); }); } app.get('/', (req, res) => { res.render('signin', { showSignInButton: true }); }); app.get('/signin',(req, res)=>{ //Initiate a Auth Code Flow >> for sign in //Pass the api scopes as well so that you received both the IdToken and accessToken getAuthCode(process.env.SIGN_UP_SIGN_IN_POLICY_AUTHORITY,apiConfig.webApiScopes, APP_STATES.LOGIN, res); }); app.get('/redirect',(req, res)=>{ if (req.query.state === APP_STATES.LOGIN) { // prepare the request for calling the web API tokenRequest.authority = process.env.SIGN_UP_SIGN_IN_POLICY_AUTHORITY; tokenRequest.scopes = apiConfig.webApiScopes; tokenRequest.code = req.query.code; confidentialClientApplication.acquireTokenByCode(tokenRequest) .then((response) => { req.session.accessToken = response.accessToken; req.session.givenName = response.idTokenClaims.given_name; console.log('\nAccessToken:' + req.session.accessToken); res.render('signin', {showSignInButton: false, givenName: response.idTokenClaims.given_name}); }).catch((error) => { console.log(error); res.status(500).send(error); }); }else{ res.status(500).send('We do not recognize this response!'); } }); //<ms_docref_api_express_route> app.get('/api', async (req, res) => { if(!req.session.accessToken){ //User is not logged in and so they can only call the anonymous API try { const response = await axios.get(apiConfig.anonymousUri); console.log('API response' + response.data); res.render('api',{data: JSON.stringify(response.data), showSignInButton: true, bg_color:'warning'}); } catch (error) { console.error(error); res.status(500).send(error); } }else{ //Users have the accessToken because they signed in and the accessToken is still in the session console.log('\nAccessToken:' + req.session.accessToken); let accessToken = req.session.accessToken; const options = { headers: { //accessToken used as bearer token to call a protected API Authorization: `Bearer ${accessToken}` } }; try { const response = await axios.get(apiConfig.protectedUri, options); console.log('API response' + response.data); res.render('api',{data: JSON.stringify(response.data), showSignInButton: false, bg_color:'success', givenName: req.session.givenName}); } catch (error) { console.error(error); res.status(500).send(error); } } }); //</ms_docref_api_express_route> /** * Sign out end point */ app.get('/signout',async (req, res)=>{ logoutUri = process.env.LOGOUT_ENDPOINT; req.session.destroy(() => { res.redirect(logoutUri); }); }); app.listen(process.env.SERVER_PORT, () => console.log(`Msal Node Auth Code Sample app listening on port !` + process.env.SERVER_PORT));
Le code du
index.js
fichier se compose de variables globales et d’itinéraires express.Variables globales :
confidentialClientConfig
: objet de configuration MSAL, utilisé pour créer l’objet d’application cliente confidentielle./** * Confidential Client Application Configuration */ const confidentialClientConfig = { auth: { clientId: process.env.APP_CLIENT_ID, authority: process.env.SIGN_UP_SIGN_IN_POLICY_AUTHORITY, clientSecret: process.env.APP_CLIENT_SECRET, knownAuthorities: [process.env.AUTHORITY_DOMAIN], //This must be an array redirectUri: process.env.APP_REDIRECT_URI, validateAuthority: false }, system: { loggerOptions: { loggerCallback(loglevel, message, containsPii) { console.log(message); }, piiLoggingEnabled: false, logLevel: msal.LogLevel.Verbose, } } }; // Initialize MSAL Node const confidentialClientApplication = new msal.ConfidentialClientApplication(confidentialClientConfig);
apiConfig
: Contient la propriétéwebApiScopes
(il doit s’agir d’un tableau), correspondant aux étendues configurées dans l’API web et accordées à l’application web. Il a également des URI vers l’API web à appeler, c’est-à-direanonymousUri
protectedUri
.const apiConfig = { webApiScopes: [`https://${process.env.TENANT_NAME}.onmicrosoft.com/tasks-api/tasks.read`], anonymousUri: 'http://localhost:5000/public', protectedUri: 'http://localhost:5000/hello' };
APP_STATES
: valeur incluse dans la requête qui est également retournée dans la réponse du jeton. Permet de différencier les réponses reçues d’Azure AD B2C.authCodeRequest
: objet de configuration utilisé pour récupérer le code d’autorisation.tokenRequest
: objet de configuration utilisé pour acquérir un jeton par code d’autorisation.sessionConfig
: objet de configuration pour la session express.getAuthCode
: méthode qui crée l’URL de la demande d’autorisation, permettant à l’utilisateur d’entrer les informations d’identification et de donner son consentement à l’application. Elle utilise lagetAuthCodeUrl
méthode, qui est définie dans la classe ConfidentialClientApplication .
Itinéraires express :
-
/
:- Il s’agit de l’entrée de l’application web et affiche la
signin
page.
- Il s’agit de l’entrée de l’application web et affiche la
-
/signin
:- Connecte l’utilisateur.
- Appelle la méthode
getAuthCode()
et transmet leauthority
pour le flux/la stratégie utilisateur Connexion et inscription,APP_STATES.LOGIN
etapiConfig.webApiScopes
à celui-ci. - Cela incite l'utilisateur final à saisir ses identifiants ou, si l'utilisateur n'a pas de compte, il peut s'inscrire.
- La réponse finale résultant de ce point de terminaison inclut un code d’autorisation de B2C retourné au point de terminaison
/redirect
.
-
/redirect
:- Il s’agit du point de terminaison défini comme URI de redirection pour l’application web dans le portail Azure.
- Il utilise le paramètre de requête dans la
state
réponse d’Azure AD B2C pour différencier les requêtes effectuées à partir de l’application web. - Si l’état de l’application est
APP_STATES.LOGIN
, le code d’autorisation acquis est utilisé pour récupérer un jeton à l’aide de laacquireTokenByCode()
méthode. Quand vous demandez un jeton à l’aide de la méthodeacquireTokenByCode
, vous utilisez les mêmes étendues que celles utilisées lors de l’acquisition du code d’autorisation. Le jeton acquis comprendaccessToken
,idToken
etidTokenClaims
. Une fois que vous avez acquis leaccessToken
, vous le placez dans une session pour l'utiliser ultérieurement afin d'appeler l'API web.
-
/api
:- Appelle l’API web.
- Si le
accessToken
n’est pas dans la session, appelez le point de terminaison d’API anonyme (http://localhost:5000/public
sinon, appelez le point de terminaison d’API protégé (http://localhost:5000/hello
).
-
/signout
:- Déconnecte l’utilisateur.
- supprime la session de l'application web et effectue un appel HTTP au point de terminaison de déconnexion d'Azure AD B2C.
Étape 3 : Exécuter l’application web et l’API
Suivez les étapes décrites dans Exécuter l’application web et l’API pour tester votre application web et votre API web.