Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Viktigt!
Från och med den 1 maj 2025 är Azure AD B2C inte längre tillgängligt att köpa för nya kunder. Läs mer i våra vanliga frågor och svar.
I den här artikeln får du lära dig hur du skapar din webbapp som anropar webb-API:et. Webb-API:et måste skyddas av Azure Active Directory B2C (Azure AD B2C). Om du vill auktorisera åtkomst till webb-API:et hanterar du begäranden som innehåller en giltig åtkomsttoken som utfärdas av Azure AD B2C.
Förutsättningar
Innan du börjar läsa och slutföra stegen i Konfigurera autentisering i ett exempel Node.js webb-API med hjälp av Azure AD B2C. Följ sedan stegen i den här artikeln för att ersätta exempelwebbappen och webb-API:et med ditt eget webb-API.
Visual Studio Code eller någon annan kodredigerare
Steg 1: Skapa ett skyddat webb-API
Följ de här stegen för att skapa ditt Node.js webb-API.
Steg 1.1: Skapa projektet
Använd Express för Node.js för att skapa ett webb-API. Gör följande för att skapa ett webb-API:
- Skapa en ny mapp med namnet
TodoList
. - Under mappen
TodoList
skapar du en fil med namnetindex.js
. - Kör i ett kommandogränssnitt
npm init -y
. Det här kommandot skapar en standardfil förpackage.json
för ditt Node.js projekt. - Kör
npm install express
i kommandogränssnittet. Det här kommandot installerar Express-ramverket.
Steg 1.2: Installera beroenden
Lägg till autentiseringsbiblioteket i ditt webb-API-projekt. Autentiseringsbiblioteket parsar HTTP-autentiseringshuvudet, validerar token och extraherar anspråk. Mer information finns i dokumentationen för biblioteket.
Om du vill lägga till autentiseringsbiblioteket installerar du paketen genom att köra följande kommando:
npm install passport
npm install passport-azure-ad
npm install morgan
Morgan-paketet är ett mellanprogram för HTTP-begärandeloggning för Node.js.
Steg 1.3: Skriva webb-API-serverkoden
index.js
Lägg till följande kod i filen:
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);
});
Anteckna följande kodfragment i index.js
filen:
Importerar passet Microsoft Entra-biblioteket
const BearerStrategy = require('passport-azure-ad').BearerStrategy;
Ange alternativ för 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 }
instansiera Passport Microsoft Entra-biblioteket med Azure AD B2C-alternativ
const bearerStrategy = new BearerStrategy(options, (token, done) => { // Send user info using the second argument done(null, { }, token); } );
Den skyddade API-slutpunkten. Den hanterar begäranden som innehåller en giltig Azure AD B2C-utfärdad åtkomsttoken. Den här slutpunkten returnerar värdet för anspråket
name
i åtkomsttoken.// 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']}); } );
Den anonyma API-slutpunkten. Webbappen kan anropa den utan att presentera en åtkomsttoken. Använd den för att felsöka ditt webb-API med anonyma anrop.
// API anonymous endpoint, returns a date to the caller. app.get('/public', (req, res) => res.send( {'date': new Date() } ));
Steg 1.4: Konfigurera webb-API:et
Lägg till konfigurationer i en konfigurationsfil. Filen innehåller information om din Azure AD B2C-identitetsprovider. Webb-API-applikationen använder den här informationen för att validera den åtkomsttoken som webbapplikationen skickar som en bärartoken.
Under projektrotmappen skapar du en
config.json
fil och lägger sedan till följande JSON-objekt i den:{ "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" } }
Uppdatera följande egenskaper i
config.json
filen:
Sektion | Nyckel | Värde |
---|---|---|
Autentiseringsuppgifter | hyresgästsnamn | Den första delen av ditt Azure AD B2C-klientnamn (till exempel fabrikamb2c ). |
Autentiseringsuppgifter | klientID | Webb-API-program-ID. Information om hur du hämtar ditt webb-API-programregistrerings-ID finns i Krav. |
Policier | policynamn | Användarflöden eller anpassad policy. Information om hur du hämtar ditt användarflöde eller din policy finns i Krav. |
resurs | omfattning | Omfången för din webb-API-programregistrering, till exempel [tasks.read] . Information om hur du hämtar ditt webb-API-omfång finns i Krav. |
Steg 2: Skapa webbnodwebbprogrammet
Följ de här stegen för att skapa Node-webbappen. Den här webbappen autentiserar en användare för att hämta en åtkomsttoken som används för att anropa nodwebb-API:et som du skapade i steg 1:
Steg 2.1: Skapa nodprojektet
Skapa en mapp för att lagra nodprogrammet, till exempel call-protected-api
.
I terminalen ändrar du katalogen till nodappmappen, till exempel
cd call-protected-api
, och körnpm init -y
. Det här kommandot skapar en standardfil för package.json för ditt Node.js projekt.Kör
npm install express
i terminalen. Det här kommandot installerar Express-ramverket.Skapa fler mappar och filer för att uppnå följande projektstruktur:
call-protected-api/ ├── index.js └── package.json └── .env └── views/ └── layouts/ └── main.hbs └── signin.hbs └── api.hbs
Mappen
views
innehåller styrfiler för webbappens användargränssnitt.
Steg 2.2: Installera beroendena
Installera paketen , dotenv
, express-handlebars
och express-session
i terminalen @azure/msal-node
genom att köra följande kommandon:
npm install dotenv
npm install express-handlebars
npm install express
npm install axios
npm install express-session
npm install @azure/msal-node
Steg 2.3: Skapa komponenter för webbappens användargränssnitt
main.hbs
Lägg till följande kod i filen:<!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>
Filen
main.hbs
finns ilayout
mappen och den bör innehålla all HTML-kod som krävs i hela programmet. Det implementerar användargränssnitt som skapats med Bootstrap 5 CSS Framework. Alla användargränssnitt som ändras från sida till sida, till exempelsignin.hbs
, placeras i platshållaren som visas som{{{body}}}
.signin.hbs
Lägg till följande kod i filen:<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>
api.hbs
Lägg till följande kod i filen:<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>
Den här sidan visar svaret från API:et. Med
bg-{{bg_color}}
klassattributet i Bootstrap-kortet kan användargränssnittet visa en annan bakgrundsfärg för de olika API-slutpunkterna.
Steg 2.4: Fullständig webbprogramserverkod
I filen
.env
lägger du till följande kod, som innehåller serverns http-port, information om appregistrering samt inloggnings- och registreringsprinciper för användarflödet.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
Ändra värdena i filerna enligt beskrivningen
.env
i Konfigurera exempelwebbappenindex.js
Lägg till följande kod i filen:/* * 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));
Koden i
index.js
filen består av globala variabler och expressvägar.Globala variabler:
confidentialClientConfig
: MSAL-konfigurationsobjektet som används för att skapa det konfidentiella klientprogramobjektet./** * 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
: InnehållerwebApiScopes
-egenskapen (dess värde måste vara en array), som är de omfång som konfigurerats i webb-API och beviljats till webbappen. Den har också URI:er till webb-API:et som ska anropas, dvsanonymousUri
. ochprotectedUri
.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
: Ett värde som ingår i begäran som också returneras i tokensvaret. Används för att skilja mellan svar som tas emot från Azure AD B2C.authCodeRequest
: Konfigurationsobjektet som används för att hämta auktoriseringskod.tokenRequest
: Konfigurationsobjektet som används för att hämta en token med auktoriseringskod.sessionConfig
: Konfigurationsobjektet för expresssession.getAuthCode
: En metod som skapar URL:en för auktoriseringsbegäran och låter användaren ange autentiseringsuppgifter och medgivande till programmet. Den användergetAuthCodeUrl
metoden, som definieras i klassen ConfidentialClientApplication .
Expressvägar:
-
/
:- Det är ingången till webbappen och visar
signin
sidan.
- Det är ingången till webbappen och visar
-
/signin
:- Loggar in användaren.
- Anropar
getAuthCode()
metoden och skickarauthority
för att hantera Logga in och registrera användarflöde/policy,APP_STATES.LOGIN
ochapiConfig.webApiScopes
till den. - Det gör att slutanvändaren uppmanas att ange sina inloggningar, eller om användaren inte har något konto kan användaren registrera sig.
- Det slutliga svaret från den här slutpunkten innehåller en auktoriseringskod från B2C som skickas tillbaka till
/redirect
slutpunkten.
-
/redirect
:- Det är slutpunkten som anges som omdirigerings-URI för webbappen i Azure Portal.
- Den använder
state
frågeparametern i Azure AD B2C:s svar för att skilja mellan begäranden som görs från webbappen. - Om apptillståndet är
APP_STATES.LOGIN
används auktoriseringskoden som hämtas för att hämta en token med hjälp avacquireTokenByCode()
metoden . När du begär en token med hjälp avacquireTokenByCode
metoden använder du samma omfång som används när du hämtar auktoriseringskoden. Den förvärvade token innehåller enaccessToken
,idToken
ochidTokenClaims
. När du har hämtataccessToken
, placerar du den i en session för senare användning för att anropa webb-API:et.
-
/api
:- Anropar webb-API:et.
-
accessToken
Om inte är i sessionen anropar du den anonyma API-slutpunkten (http://localhost:5000/public
), annars anropar du den skyddade API-slutpunkten (http://localhost:5000/hello
).
-
/signout
:- Loggar ut användaren.
- rensar webbappsessionen och gör ett http-anrop till slutpunkten för utloggning av Azure AD B2C.
Steg 3: Kör webbappen och API:et
Följ stegen i Kör webbappen och API:et för att testa webbappen och webb-API:et.