Aracılığıyla paylaş


Öğretici: Microsoft kimlik platformunu kullanarak node/Express.js web uygulamasına oturum açma ekleme

Şunlar için geçerlidir: Aşağıdaki içeriğin iş gücü kiracıları için geçerli olduğunu gösteren beyaz onay işareti simgesine sahip yeşil daire. İş gücü kiracıları Aşağıdaki içeriğin dış kiracılar için geçerli olduğunu gösteren beyaz onay işareti simgesine sahip yeşil daire. Dış kiracılar (daha fazla bilgi edinin)

Bu öğreticide Node/Express web uygulamanıza oturum açma ve oturum kapatma mantığı eklersiniz. Bu kod, harici bir kiracıda veya bir iş gücü kiracısındaki çalışanlar için, müşterilere yönelik uygulamanızda kullanıcıların oturum açmasını sağlar.

Bu öğretici, 3 bölümden oluşan öğretici serisinin 2. bölümüdür.

Bu öğreticide şunları yapacaksınız:

  • Oturum açma ve oturum kapatma mantığı ekleme
  • Kimlik belirteci taleplerini görüntüleme
  • Uygulamayı çalıştırın ve oturum açma ve oturum kapatma deneyimini test edin.

Önkoşullar

MSAL yapılandırma nesnesi oluşturma

Kod düzenleyicinizde authConfig.js dosyasını açın ve aşağıdaki kodu ekleyin:

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
};

msalConfig nesnesi, kimlik doğrulama akışlarınızın davranışını özelleştirmek için kullandığınız bir dizi yapılandırma seçeneği içerir.

authConfig.js dosyanızda şunu değiştirin:

  • Daha önce kaydettiğiniz uygulamanın İstemci Kimliği (Application ID) ile Enter_the_Application_Id_Here.

  • Enter_the_Tenant_Subdomain_Here ve dış Dizin (kiracı) alt etki alanı ile değiştirin. Örneğin, kiracı birincil etki alanınız contoso.onmicrosoft.comise contosokullanabilirsiniz. Kiracı adınız yoksa, kiracı ayrıntılarınızı nasıl okuyacağınızı öğrenin. Bu değer yalnızca dış kiracıiçin gereklidir.

  • Daha önce kopyaladığınız uygulama gizli anahtar değeriyle Enter_the_Client_Secret_Here.

  • Uygulamanızın çağrı yapacağı Microsoft Graph API'nin bulut örneği olan Enter_the_Graph_Endpoint_Here. https://graph.microsoft.com// değerini kullanın (sondaki eğik çizgiyi dahil edin)

Yapılandırma bilgilerinizi depolamak için .env dosyasını kullanırsanız:

  1. Kod düzenleyicinizde .env dosyasını açın ve aşağıdaki kodu ekleyin.

        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
    
  2. Yer tutucuyu değiştirin:

    1. Enter_the_Application_Id_Here, daha önce açıklandığı gibi Enter_the_Tenant_Subdomain_Here ve Enter_the_Client_Secret_Here.
    2. Uygulamanızın kayıtlı olduğu Azure bulut örneğinde Enter_the_Cloud_Instance_Id_Here kullanın. https://login.microsoftonline.com/'ı değeri olarak kullanın (sondaki eğik çizgiyi dahil edin). Bu değer yalnızcaiş gücü kiracısı için gereklidir.
    3. aaaabbbb-0000-cccc-1111-dddd2222eeeee Enter_the_Tenant_ID_herecontoso.microsoft.comgibi iş gücü Kiracı Kimliği veya Birincil etki alanıyla . Bu değer yalnızcaiş gücü kiracısı için gereklidir.

msalConfig dosyasındaki REDIRECT_URI, TENANT_SUBDOMAIN, GRAPH_ME_ENDPOINT, POST_LOGOUT_REDIRECT_URI ve değişkenleri dışarı aktararak diğer dosyalarda erişilebilir hale getirirsiniz.

Uygulamanızın yetkili URL'si

Dış ve iş gücü kiracıları için başvuru yetkilileri farklı görünür. Aşağıda gösterildiği gibi oluşturun:

//Authority for workforce tenant
authority: process.env.CLOUD_INSTANCE + process.env.TENANT_ID

Özel URL alan adı kullanma (İsteğe bağlı)

Özel URL etki alanları iş gücü kiracılarında desteklenmez.

Hızlı yollar ekleme

Express yolları, oturum açma, oturumu kapatma ve kimlik belirteci taleplerini görüntüleme gibi işlemleri yürütmemizi sağlayan uç noktaları sağlar.

Uygulama giriş noktası

Kod düzenleyicinizde routes/index.jsdosyasını açın ve aşağıdaki kodu ekleyin:

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;

/ yolu, uygulamanın giriş noktasıdır. Daha önce Uygulama kullanıcı arabirimi bileşenlerini derlemebölümünde oluşturduğunuz views/index.hbs görünümünü işler. isAuthenticated, görünümde gördüklerinizi belirleyen boole değişkenidir.

Oturum aç ve çıkış yap

  1. Kod düzenleyicinizde routes/auth.jsdosyasını açın ve aşağıdaki kodu ekleyin:

    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;
    
  2. Kod düzenleyicinizde denetleyici/authController.js dosyasını açın ve aşağıdaki kodu ekleyin:

    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);
    };
    
    
  3. Kod düzenleyicinizde auth/AuthProvider.js dosyasını açın ve aşağıdaki kodu ekleyin:

    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;
    
    

    /signin, /signout ve /redirect yolları yollar/auth.js dosyasında tanımlanır, ancak bunların mantığını kimlik doğrulaması/AuthProvider.js sınıfında uygularsınız.

  • login yöntemi /signin yolu işler:

    • Kimlik doğrulama kodu akışının ilk ayağını tetikleyerek oturum açma akışını başlatır.

    • Daha önce oluşturduğunuz MSAL yapılandırma nesnesini kullanarak msalConfig örneği başlatır.

          const msalInstance = this.getMsalInstance(this.config.msalConfig);
      

      getMsalInstance yöntemi şu şekilde tanımlanır:

          getMsalInstance(msalConfig) {
              return new msal.ConfidentialClientApplication(msalConfig);
          }
      
    • Kimlik doğrulama kodu akışının ilk ayağı bir yetkilendirme kodu isteği URL'si oluşturur, ardından yetkilendirme kodunu almak için bu URL'ye yönlendirir. Bu ilk aşama redirectToAuthCodeUrl yöntemiyle uygulanır. MSAL getAuthCodeUrl yöntemini kullanarak yetkilendirme kodu URL'si oluşturma yöntemimize dikkat edin.

      //...
      const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest);
      //...
      

      Ardından yetkilendirme kodu URL'sinin kendisine yönlendiririz.

      //...
      res.redirect(authCodeUrlResponse);
      //...
      
  • handleRedirect yöntemi /redirect yolu işler:

    • Önceki aşamalarda Microsoft Entra yönetim merkezinde web uygulaması için bu URL'yi Yönlendirme URI'si olarak ayarladınız, Hızlı Başlangıç:örnek bir web uygulamasında kullanıcıları oturum açmaları için.

    • Bu uç nokta, kimlik doğrulama kodu akışının ikinci ayağını uygular. MSAL'nin acquireTokenByCode yöntemini kullanarak kimlik belirteci istemek için yetkilendirme kodunu kullanır.

      //...
      const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body);
      //...
      
    • Yanıt aldıktan sonra Express oturumu oluşturabilir ve istediğiniz bilgileri depolayabilirsiniz. isAuthenticated eklemeniz ve trueolarak ayarlamanız gerekir:

      //...        
      req.session.idToken = tokenResponse.idToken;
      req.session.account = tokenResponse.account;
      req.session.isAuthenticated = true;
      //...
      
  • logout yöntemi /signout yolu işler:

    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);
        });
    }
    
    • Oturumu kapatma isteğini başlatır.

    • Kullanıcının uygulama oturumunu kapatmak istediğinizde, kullanıcının oturumunu sonlandırmak yeterli değildir. Kullanıcıyı logoutUri yönlendirmelisiniz. Aksi takdirde, kullanıcı kimlik bilgilerini yeniden girmeden uygulamalarınıza yeniden kimlik doğrulaması yapabilir. Kiracınızın adı contosoise, logoutUrihttps://contoso.ciamlogin.com/contoso.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000benzer görünür.

Uygulamanız için oturum kapatma URI'si ve otorite metaveri uç noktası

Uygulamanın oturum kapatma URI'si logoutUri ve yetkili meta veri uç noktası endpoint, dış ve iş gücü kiracıları için farklı görünür. Aşağıda gösterildiği gibi oluşturun:

//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`;

Kimlik belirteci taleplerini görüntüleme

Kod düzenleyicinizde routes/users.jsdosyasını açın ve aşağıdaki kodu ekleyin:

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;

Kullanıcının kimliği doğrulanırsa, /id yolu views/id.hbs görünümünü kullanarak kimlik belirteci taleplerini görüntüler. Bu görünümü daha önce Uygulama UI bileşenleri oluşturiçinde eklediniz.

Belirli bir kimlik belirtici talebini, örneğin verilen ad, ayıklamak için:

const givenName = req.session.account.idTokenClaims.given_name

Web uygulamanızı sonlandırma

  1. Kod düzenleyicinizde app.js dosyasını açın, ardından app.js kodunu bu dosyaya ekleyin.

  2. Kod düzenleyicinizde server.js dosyasını açın, ardından server.js kodunu bu dosyaya ekleyin.

  3. Kod düzenleyicinizde package.json dosyasını açın ve scripts özelliğini şu şekilde güncelleştirin:

    "scripts": {
    "start": "node server.js"
    }
    

Node/Express.js web uygulamasını çalıştırma ve test edin

Bu noktada düğüm web uygulamanızı test edebilirsiniz.

  1. Test kullanıcısı oluşturmak için Yeni Kullanıcı Oluşturma adımlarını kiracı iş gücü üzerinde kullanın. Kiracıya erişiminiz yoksa kiracı yöneticinizden kullanıcıyı sizin için oluşturmasını isteyin.

  2. Sunucuyu başlatmak için proje dizininden aşağıdaki komutları çalıştırın:

    npm start
    
  3. Tarayıcınızı açın ve ardından http://localhost:3000'a gidin. Sayfayı aşağıdaki ekran görüntüsüne benzer şekilde görmeniz gerekir:

    Node.js web uygulamasında oturum açma ekran görüntüsü.

  4. Oturum açma işlemini başlatmak için Oturum aç'a seçin. İlk kez oturum açtığınızda, aşağıdaki ekran görüntüsünde gösterildiği gibi uygulamanın oturum açmasına ve profilinize erişmesine izin vermek için onay vermeniz istenir:

    Kullanıcı onayı ekranını gösteren ekran görüntüsü

Başarıyla oturum açtıktan sonra uygulamanın giriş sayfasına yeniden yönlendirilirsiniz.

Sonraki adım

Eğitim: Node/Express.js web uygulamanızMicrosoft Graph API'sini çağırma.