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.
Důležité
Od 1. května 2025 už nebude Azure AD B2C k dispozici k nákupu pro nové zákazníky. Další informace najdete v našich nejčastějších dotazech.
V tomto článku se dozvíte, jak vytvořit webovou aplikaci, která volá vaše webové rozhraní API. Webové rozhraní API musí být chráněné službou Azure Active Directory B2C (Azure AD B2C). Pokud chcete autorizovat přístup k webovému rozhraní API, obsluhujete požadavky, které obsahují platný přístupový token vydaný službou Azure AD B2C.
Požadavky
Než začnete, přečtěte si a dokončete kroky v části Konfigurace ověřování v ukázkovém rozhraní webového API Node.js pomocí Azure AD B2C. Potom podle kroků v tomto článku nahraďte ukázkovou webovou aplikaci a webové rozhraní API vlastním webovým rozhraním API.
Visual Studio Code nebo jiný editor kódu
Krok 1: Vytvoření chráněného webového rozhraní API
Podle těchto kroků vytvořte webové rozhraní API pro Node.js.
Krok 1.1: Vytvoření projektu
K vytvoření webového rozhraní API použijte Express pro Node.js . Pokud chcete vytvořit webové rozhraní API, postupujte takto:
- Vytvořte novou složku s názvem
TodoList
. -
TodoList
Ve složce vytvořte soubor s názvemindex.js
. - V příkazovém prostředí spusťte
npm init -y
. Tento příkaz vytvoří výchozí souborpackage.json
pro váš projekt Node.js. - V příkazovém prostředí spusťte
npm install express
. Tento příkaz nainstaluje architekturu Express.
Krok 1.2: Instalace závislostí
Přidejte knihovnu ověřování do projektu webového rozhraní API. Knihovna ověřování analyzuje hlavičku ověřování HTTP, ověří token a extrahuje deklarace identity. Další informace najdete v dokumentaci ke knihovně.
Pokud chcete přidat knihovnu ověřování, nainstalujte balíčky spuštěním následujícího příkazu:
npm install passport
npm install passport-azure-ad
npm install morgan
Balíček morgan je middleware pro protokolování HTTP požadavků pro Node.js.
Krok 1.3: Napsání kódu serveru webového rozhraní API
index.js
Do souboru přidejte následující kód:
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);
});
Poznamenejte si následující fragmenty kódu v index.js
souboru:
Importuje knihovnu Microsoft Entra passport
const BearerStrategy = require('passport-azure-ad').BearerStrategy;
Nastaví možnosti 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 }
Vytvoření instance knihovny Microsoft Entra passport pomocí možností Azure AD B2C
const bearerStrategy = new BearerStrategy(options, (token, done) => { // Send user info using the second argument done(null, { }, token); } );
Koncový bod chráněného rozhraní API. Slouží k žádostem, které zahrnují platný přístupový token vydaný službou Azure AD B2C. Tento koncový bod vrátí hodnotu
name
nároku uvnitř přístupového tokenu.// 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']}); } );
Anonymní koncový bod rozhraní API. Webová aplikace ji může volat bez prezentování přístupového tokenu. Slouží k ladění webového rozhraní API pomocí anonymních volání.
// API anonymous endpoint, returns a date to the caller. app.get('/public', (req, res) => res.send( {'date': new Date() } ));
Krok 1.4: Konfigurace webového rozhraní API
Přidejte konfigurace do konfiguračního souboru. Soubor obsahuje informace o vašem zprostředkovateli identity Azure AD B2C. Aplikace webového rozhraní API tyto informace používá k ověření přístupového tokenu, který webová aplikace předává jako nosný token.
V kořenové složce projektu vytvořte
config.json
soubor a pak do ní přidejte následující objekt JSON:{ "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" } }
config.json
V souboru aktualizujte následující vlastnosti:
Oddíl | Klíč | Hodnota |
---|---|---|
pověření | názevNájemce | První část názvu klienta Azure AD B2C (například fabrikamb2c ). |
pověření | Klientský ID | ID webové API aplikace. Informace o tom, jak získat ID registrace aplikace webového rozhraní API, najdete v tématu Požadavky. |
politiky | název politiky | Toky uživatelů nebo vlastní pravidla. Jak získat tok uživatele nebo zásady, naleznete v sekci Požadavky. |
zdroj | rozsah působnosti | Rozsahy registrace vaší aplikace webového rozhraní API, například [tasks.read] . Informace o tom, jak získat obor webového rozhraní API, najdete v tématu Požadavky. |
Krok 2: Vytvoření webové aplikace Node
Pomocí těchto kroků vytvořte webovou aplikaci Node. Tato webová aplikace ověřuje uživatele, aby získal přístupový token, který se používá k volání webového rozhraní API Node, které jste vytvořili v kroku 1:
Krok 2.1: Vytvoření projektu uzlu
Vytvořte složku pro uložení aplikace uzlu, například call-protected-api
.
V terminálu změňte adresář do složky aplikace node, například
cd call-protected-api
a spusťtenpm init -y
. Tento příkaz vytvoří výchozí soubor package.json pro váš projekt Node.js.V terminálu spusťte
npm install express
. Tento příkaz nainstaluje architekturu Express.Vytvořte další složky a soubory, abyste dosáhli následující struktury projektu:
call-protected-api/ ├── index.js └── package.json └── .env └── views/ └── layouts/ └── main.hbs └── signin.hbs └── api.hbs
Složka
views
obsahuje soubory úchytů pro uživatelské rozhraní webové aplikace.
Krok 2.2: Instalace závislostí
V terminálu nainstalujte balíčky dotenv
, express-handlebars
, express-session
a @azure/msal-node
spuštěním následujících příkazů:
npm install dotenv
npm install express-handlebars
npm install express
npm install axios
npm install express-session
npm install @azure/msal-node
Krok 2.3: Sestavení komponent uživatelského rozhraní webové aplikace
main.hbs
Do souboru přidejte následující kód:<!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>
Soubor
main.hbs
je velayout
složce a měl by obsahovat libovolný kód HTML, který se vyžaduje v celé aplikaci. Implementuje uživatelské rozhraní vytvořené pomocí architektury CSS Bootstrap 5. Jakékoli uživatelské rozhraní, které se změní ze stránky na stránku, napříkladsignin.hbs
, se umístí do zástupného symbolu zobrazeného jako{{{body}}}
.signin.hbs
Do souboru přidejte následující kód:<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
Do souboru přidejte následující kód:<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>
Na této stránce se zobrazí odpověď z rozhraní API. Atribut
bg-{{bg_color}}
třídy na kartě Bootstrap umožňuje uživatelskému rozhraní zobrazit jinou barvu pozadí pro různé koncové body rozhraní API.
Krok 2.4: Dokončení kódu serveru webových aplikací
.env
Do souboru přidejte následující kód, který zahrnuje port HTTP serveru, podrobnosti o registraci aplikace a přihlášení a registraci toku uživatele nebo podrobnosti o zásadách: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
Upravte hodnoty v souborech
.env
, jak je vysvětleno v části Konfigurace ukázkové webové aplikace.index.js
Do souboru přidejte následující kód:/* * 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));
Kód v
index.js
souboru se skládá z globálních proměnných a expresních tras.Globální proměnné:
confidentialClientConfig
: Objekt konfigurace MSAL, který slouží k vytvoření důvěrného objektu klientské aplikace./** * 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
: ObsahujewebApiScopes
vlastnost (hodnota musí být pole), což jsou obory nakonfigurované ve webovém rozhraní API a udělené webové aplikaci. Obsahuje také identifikátory URI webového rozhraní API, které se mají volat, tjanonymousUri
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
: Hodnota zahrnutá v požadavku, který se vrátí také v odpovědi tokenu. Používá se k rozlišení odpovědí přijatých z Azure AD B2C.authCodeRequest
: Objekt konfigurace použitý k načtení autorizačního kódu.tokenRequest
: Objekt konfigurace použitý k získání tokenu autorizačním kódem.sessionConfig
: Objekt konfigurace pro expresní relaci.getAuthCode
: Metoda, která vytvoří adresu URL žádosti o autorizaci, která umožní zadání přihlašovacích údajů uživatele a souhlas s aplikací. Používá metodugetAuthCodeUrl
, která je definována ve třídě ConfidentialClientApplication .
Expresní trasy:
-
/
:- Je to položka webové aplikace a vykreslí
signin
stránku.
- Je to položka webové aplikace a vykreslí
-
/signin
:- Přihlásí se k uživateli.
- Volá
getAuthCode()
metodu a předává metoduauthority
přihlášení a registraci toku/zásadAPP_STATES.LOGIN
uživatele aapiConfig.webApiScopes
do ní. - To způsobí, že koncový uživatel bude vyzván k zadání přihlašovacích údajů nebo pokud uživatel nemá účet, může se zaregistrovat.
- Konečná odpověď vyplývající z tohoto koncového bodu zahrnuje autorizační kód z B2C vystavený zpět do koncového
/redirect
bodu.
-
/redirect
:- Je to koncový bod nastavený jako identifikátor URI přesměrování pro webovou aplikaci na webu Azure Portal.
- Používá
state
parametr dotazu v odpovědi Azure AD B2C k rozlišení požadavků provedených z webové aplikace. - Pokud je
APP_STATES.LOGIN
stav aplikace , autorizační kód získaný se použije k načtení tokenuacquireTokenByCode()
pomocí metody. Při vyžádání tokenu pomocíacquireTokenByCode
metody použijete stejné obory, které jste použili při získávání autorizačního kódu. Získaný token obsahuje symbolaccessToken
,idToken
aidTokenClaims
. Jakmile hoaccessToken
získáte, vložíte ho do relace pro pozdější použití k volání webového rozhraní API.
-
/api
:- Volá webové rozhraní API.
-
accessToken
Pokud není v relaci, zavolejte anonymní koncový bod rozhraní API (http://localhost:5000/public
), jinak zavolejte chráněný koncový bod rozhraní API (http://localhost:5000/hello
).
-
/signout
:- Odhlásí uživatele.
- vymaže relaci webové aplikace a provede volání HTTP do koncového bodu odhlášení Azure AD B2C.
Krok 3: Spuštění webové aplikace a rozhraní API
Postupujte podle kroků v části Spuštění webové aplikace a rozhraní API a otestujte webovou aplikaci a webové rozhraní API.