Öğretici: Node.js daemon uygulamanızdan web API'si çağırma

Bu öğreticide , Açık Yetkilendirme (OAuth) 2.0 istemci kimlik bilgileri verme akışını kullanarak Node.js daemon istemci uygulamanızı hazırlama ve ardından web API'sini çağırmak için erişim belirteci almak üzere yapılandırma işlemleri gösterilmektedir. Uygulamanıza yetkilendirme eklemeyi basitleştirmek amacıyla Node için Microsoft Authentication Library (MSAL) kullanarak bir Node.js uygulaması oluşturacaksınız.

Bu rehberde;

  • Web API'sinin uygulama rollerini yapılandırma
  • Daemon uygulamasına izin verme
  • Visual Studio Code'da bir Node.js uygulaması oluşturun ve bağımlılıkları yükleyin.
  • web API'sini çağırmak için erişim belirteci almak için Node.js uygulamasını etkinleştirin.

Önkoşullar

  • Herhangi bir kuruluş dizinindeki hesaplar ve kişisel Microsoft hesapları için yapılandırılmış yeni bir istemci uygulamasını Microsoft Entra yönetim merkezine kaydedin. Daha fazla bilgi için Bir uygulamayı kaydetme bölümüne bakın. Daha sonra kullanmak üzere uygulamaya Genel Bakış sayfasından aşağıdaki değerleri kaydedin:
    • Uygulama (istemci) kimliği
    • Dizin (kullanıcı) kimliği
    • Dizin (kiracı) etki alanı adı (örneğin, contoso.onmicrosoft.com veya contoso.com).
  • İstemci uygulama kaydınıza bir istemci gizli anahtarı ekleyin. Üretim uygulamalarında istemci sırlarını kullanmayın. Bunun yerine sertifikaları veya federasyon kimlik bilgilerini kullanın. Daha fazla bilgi için bkz. Uygulamanıza kimlik bilgileri ekleme.
  • Çalışan ve istekleri kabul etmeye hazır korumalı bir web API'si. Web API'nizin HTTPS aracılığıyla aşağıdaki uç noktaları kullanıma sunun:
    • GET /api/todolist ile tüm yapılacakları görüntülemek için.
    • Bir TODO eklemek için POST /api/todolist.
  • Node.js.
  • React uygulamalarını destekleyen tüm tümleşik geliştirme ortamları (IDE) kullanılabilse de, bu öğreticide Visual Studio Code kullanılmaktadır.

Uygulama rollerini yapılandırma

bir API'nin, istemci uygulamalarının kendileri gibi bir erişim belirteci elde etmesi için uygulamalar için uygulama izni olarak da adlandırılan en az bir uygulama rolü yayımlaması gerekir. Uygulama izinleri, istemci uygulamalarının kullanıcıların oturum açmasına gerek kalmadan kendi kimliklerini başarıyla doğrulayabilmesi için API'lerin yayımlaması gereken izin türüdür. Uygulama izni yayımlamak için şu adımları izleyin:

  1. Uygulama kayıtları sayfasında, oluşturduğunuz uygulamayı (ciam-ToDoList-api gibi) seçerek Genel Bakış sayfasını açın.

  2. Yönetaltında Uygulama rolleriseçin.

  3. Uygulama rolü oluştur'u seçin, ardından aşağıdaki değerleri girin ve ardından Uygula'yı seçerek değişikliklerinizi kaydedin:

    Mülkiyet Değer
    Ekran adı ToDoList.Read.All
    İzin verilen üye türleri Uygulamaları
    Değer ToDoList.Read.All
    Açıklama Uygulamanın 'TodoListApi' kullanarak her kullanıcının ToDo listesini okumasına izin ver
    Bu uygulama rolünü etkinleştirmek istiyor musunuz? İşaretli tutun
  4. Uygulama rolü oluştur'u yeniden seçin, ardından ikinci uygulama rolü için aşağıdaki değerleri girin ve ardından Değişikliklerinizi kaydetmek için Uygula'yı seçin:

    Mülkiyet Değer
    Ekran adı ToDoList.ReadWrite.All
    İzin verilen üye türleri Uygulamaları
    Değer ToDoList.ReadWrite.All
    Açıklama Uygulamanın 'ToDoListApi' kullanarak her kullanıcının ToDo listesini okumasına ve yazmasına izin ver
    Bu uygulama rolünü etkinleştirmek istiyor musunuz? İşaretli tutun

Idtyp belirteci talebini yapılandırmak

Web API'sinin bir uygulama belirteci mi yoksa uygulama + kullanıcı belirteci mi olduğunu belirlemesine yardımcı olmak için idtyp isteğe bağlı talebi ekleyebilirsiniz. Aynı amaçla scp ve rol taleplerinin bir birleşimini kullanabilirsiniz ancak idtyp talebi, uygulama belirtecini ve uygulama + kullanıcı belirtecini birbirinden ayırt etmenin en kolay yoludur. Örneğin, belirteç yalnızca bir uygulama belirteci olduğunda, bu talebin değeri uygulama olur.

Daemon uygulamasına API izinleri verme

  1. Uygulama kayıtları sayfasında, oluşturduğunuz uygulamayı (ciam-client-app gibi) seçin.

  2. Yönet altında API izinleri'ni seçin.

  3. Yapılandırılmış izinleraltında İzinekle'yi seçin.

  4. Kuruluşumun kullandığı API'ler sekmesini seçin.

  5. API'ler listesinde ciam-ToDoList-api gibi API'yi seçin.

  6. Uygulama izinleri seçeneğini belirleyin. Uygulama kendi adıyla oturum açtığında ancak kullanıcı adına oturum açmadığı için bu seçeneği seçeriz.

  7. İzinler listesinden TodoList.Read.All, ToDoList.ReadWrite.All öğesini seçin (gerekirse arama kutusunu kullanın).

  8. İzin ekle düğmesini seçin.

  9. Bu noktada izinleri doğru atamış olursunuz. Ancak, daemon uygulaması kullanıcıların bu uygulamayla etkileşim kurmasına izin vermediğinden, kullanıcılar bu izinlere onay veremez. Bu sorunu çözmek için, yönetici olarak kiracıdaki tüm kullanıcılar adına bu izinleri onaylamanız gerekir:

    1. Yönetici iznini <[kendi kiracı adınız]> için verin, ardından Evet'i seçin.
    2. Yenile'yi seçin ve ardından Kiracı adınız için < Verildi seçeneğinin her iki izin için de > altında göründüğünü doğrulayın.

Node.js daemon projesini oluşturma

Node.js daemon uygulamanızı barındırmak için ciam-call-api-node-daemongibi bir klasör oluşturun:

  1. Terminalinizde dizini node daemon uygulama klasörünüzle değiştirin(cd ciam-call-api-node-daemongibi) ve npm init -yçalıştırın. Bu komut, Node.js projeniz için varsayılan bir package.json dosyası oluşturur. Bu komut, Node.js projeniz için varsayılan bir package.json dosyası oluşturur.

  2. Aşağıdaki proje yapısını elde etmek için ek klasörler ve dosyalar oluşturun:

        ciam-call-api-node-daemon/
        ├── auth.js
        └── authConfig.js
        └── fetch.js
        └── index.js 
        └── package.json
    

Uygulama bağımlılıklarını yükleme

Terminalinizde, aşağıdaki komutu çalıştırarak axios, yargs ve @azure/msal-node paketlerini yükleyin:

npm install axios yargs @azure/msal-node   

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();

/**
 * 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
        authority: process.env.AUTHORITY || 'https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/', // Replace "Enter_the_Tenant_Subdomain_Here" with your tenant subdomain
        clientSecret: process.env.CLIENT_SECRET || 'Enter_the_Client_Secret_Here', // Client secret generated from the app 
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: 'Info',
        },
    },
};    
const protectedResources = {
    apiToDoList: {
        endpoint: process.env.API_ENDPOINT || 'https://localhost:44351/api/todolist',
        scopes: [process.env.SCOPES || 'api://Enter_the_Web_Api_Application_Id_Here'],
    },
};

module.exports = {
    msalConfig,
    protectedResources,
};

msalConfig nesnesi, yetkilendirme akışı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 istemci daemon uygulamasının Uygulama (istemci) kimliğiyle Enter_the_Application_Id_Here.

  • Enter_the_Tenant_Subdomain_Here ile dizin (kiracı) alt alan adını değiştirin. Örneğin, kiracının birincil alan adı contoso.onmicrosoft.com ise contoso kullanın. Kiracı adınız yoksa, kiracı ayrıntılarınızı nasıl okuyacağınızıöğrenin.

  • Daha önce kopyaladığınız gizli değer ile Enter_the_Client_Secret_Here istemci daemon uygulamasını kullanın.

  • Daha önce kopyaladığınız web API uygulamasının Uygulama (istemci) kimliğini Enter_the_Web_Api_Application_Id_Here ile değiştirin.

değişkenindeki scopes özelliğininprotectedResources, önkoşulların bir parçası olarak kaydettiğiniz web API'sinin kaynak tanımlayıcısı (uygulama kimliği URI'si) olduğuna dikkat edin. Tam kapsam URI'si api://Enter_the_Web_Api_Application_Id_Here/.default'e şuna benzer.

Erişim belirteci alma

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

const msal = require('@azure/msal-node');
const { msalConfig, protectedResources } = require('./authConfig');
/**
 * With client credentials flows permissions need to be granted in the portal by a tenant administrator.
 * The scope is always in the format '<resource-appId-uri>/.default'. For more, visit:
 * https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
 */
const tokenRequest = {
    scopes: [`${protectedResources.apiToDoList.scopes}/.default`],
};

const apiConfig = {
    uri: protectedResources.apiToDoList.endpoint,
};

/**
 * Initialize a confidential client application. For more info, visit:
 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/initialize-confidential-client-application.md
 */
const cca = new msal.ConfidentialClientApplication(msalConfig);
/**
 * Acquires token with client credentials.
 * @param {object} tokenRequest
 */
async function getToken(tokenRequest) {
    return await cca.acquireTokenByClientCredential(tokenRequest);
}

module.exports = {
    apiConfig: apiConfig,
    tokenRequest: tokenRequest,
    getToken: getToken,
};

Kodda:

  • tokenRequest ve apiConfig nesnesini hazırlayın. tokenRequest, erişim belirteci talep ettiğiniz kapsamı içerir. Kapsam şu şekilde görünür: api://Enter_the_Web_Api_Application_Id_Here/.default. apiConfig nesnesi web API'nizin uç noktasını içerir. OAuth 2.0 istemci kimlik bilgileri akışı hakkında daha fazla bilgi edinin.

  • msalConfig nesnesini ConfidentialClientApplication sınıfının oluşturucusna geçirerek gizli bir istemci örneği oluşturursunuz.

    const cca = new msal.ConfidentialClientApplication(msalConfig);
    
  • Ardından erişim belirteci almak için acquireTokenByClientCredential işlevini kullanırsınız. Bu mantığı getToken işlevinde uygularsınız:

    cca.acquireTokenByClientCredential(tokenRequest);
    

Erişim belirteci aldıktan sonra bir API çağırabilirsiniz.

API çağırma

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

const axios = require('axios');

/**
 * Calls the endpoint with authorization bearer token.
 * @param {string} endpoint
 * @param {string} accessToken 
 */
async function callApi(endpoint, accessToken) {

    const options = {
        headers: {
            Authorization: `Bearer ${accessToken}`
        }
    };

    console.log('request made to web API at: ' + new Date().toString());

    try {
        const response = await axios.get(endpoint, options);
        return response.data;
    } catch (error) {
        console.log(error)
        return error;
    }
};

module.exports = {
    callApi: callApi
};

Bu kodda, erişim belirtecini istek Authorization üst bilgisine taşıyıcı belirteç olarak geçirerek web API'sine bir çağrı yaparsınız:

 Authorization: `Bearer ${accessToken}`

Daha önce aldığınız erişim belirtecini Erişim belirteci almaiçinde kullanırsınız.

Web API'si isteği aldıktan sonra bunu değerlendirir ve bunun bir uygulama isteği olduğunu belirler. Erişim belirteci geçerliyse, web API'si istenen verileri döndürür. Aksi takdirde, API bir 401 Unauthorized HTTP hatası döndürür.

Daemon uygulamanızı sonlandırın

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

#!/usr/bin/env node

// read in env settings

require('dotenv').config();

const yargs = require('yargs');
const fetch = require('./fetch');
const auth = require('./auth');

const options = yargs
    .usage('Usage: --op <operation_name>')
    .option('op', { alias: 'operation', describe: 'operation name', type: 'string', demandOption: true })
    .argv;

async function main() {
    console.log(`You have selected: ${options.op}`);

    switch (yargs.argv['op']) {
        case 'getToDos':
            try {
                const authResponse = await auth.getToken(auth.tokenRequest);
                const todos = await fetch.callApi(auth.apiConfig.uri, authResponse.accessToken);                
            } catch (error) {
                console.log(error);
            }

            break;
        default:
            console.log('Select an operation first');
            break;
    }
};

main();

Bu kod, uygulamanızın giriş noktasıdır. Node.js uygulamaları için yargs JavaScript komut satırı bağımsız değişken ayrıştırma kütüphanesini kullanarak etkileşimli olarak bir erişim belirteci alır ve sonra API'yi çağırırsınız. Daha önce tanımladığınız getToken ve callApi işlevlerini kullanırsınız:

const authResponse = await auth.getToken(auth.tokenRequest);
const todos = await fetch.callApi(auth.apiConfig.uri, authResponse.accessToken);                

Daemon uygulamasını ve API'sini çalıştırma ve test edin

Bu noktada istemci daemon uygulamanızı ve web API'nizi test etmeye hazırsınız:

  1. Web API'nizi başlatmak için ASP.NET web API'sinin güvenliğini sağlama öğreticisinde öğrendiğiniz adımları kullanın. Web API'niz artık istemci isteklerine hizmet etmeye hazırdır. web API'nizi 44351 dosyasında belirtildiği gibi bağlantı noktası çalıştırmıyorsanız, authConfig.js dosyasını doğru web API'sinin bağlantı noktası numarasını kullanacak şekilde güncelleştirdiğinizden emin olun.

  2. Terminalinizde, ciam-call-api-node-daemongibi daemon Node.js uygulamanızı içeren proje klasöründe olduğunuzdan emin olun ve aşağıdaki komutu çalıştırın:

    node . --op getToDos
    

Daemon uygulamanız ve web API'niz başarıyla çalıştırılırsa, konsol pencerenizde aşağıdaki JSON dizisine benzer şekilde web API uç noktası todos değişkeni tarafından döndürülen verileri bulmanız gerekir:

{
    id: 1,
    owner: '3e8....-db63-43a2-a767-5d7db...',
    description: 'Pick up grocery'
},
{
    id: 2,
    owner: 'c3cc....-c4ec-4531-a197-cb919ed.....',
    description: 'Finish invoice report'
},
{
    id: 3,
    owner: 'a35e....-3b8a-4632-8c4f-ffb840d.....',
    description: 'Water plants'
}

Sonraki adım