Aracılığıyla paylaş


Node.js uygulamasını ADAL'dan MSAL'ye geçirme

Düğüm için Microsoft Kimlik Doğrulama Kitaplığı (MSAL Node) artık Microsoft kimlik platformu kayıtlı uygulamalarınız için kimlik doğrulamasını ve yetkilendirmeyi etkinleştirmek için önerilen SDK'dır. Bu makale, uygulamalarınızı Düğüm için Active Directory Kimlik Doğrulama Kitaplığı'ndan (ADAL Düğümü) MSAL Düğümü'ne geçirmek için izlenmesi gereken önemli adımları kapsar.

Önkoşullar

  • Düğüm sürüm 10, 12, 14, 16 veya 18. Sürüm desteğiyle ilgili nota bakın

Uygulama kayıt ayarlarını güncelleştirme

ADAL Düğümü ile çalışırken büyük olasılıkla Azure AD v1.0 uç noktasını kullanıyordunuz. ADAL'dan MSAL'ye geçen uygulamalar Azure AD v2.0 uç noktasına geçmelidir.

MSAL'yi yükleme ve içeri aktarma

  1. npm aracılığıyla MSAL Node paketini yükleyin:
  npm install @azure/msal-node
  1. Bundan sonra kodunuzda MSAL Düğümünü içeri aktarin:
  const msal = require('@azure/msal-node');
  1. Son olarak, ADAL Node paketini kaldırın ve kodunuzdaki başvuruları kaldırın:
  npm uninstall adal-node

MSAL'ı başlatma

ADAL Düğümü'nde, farklı kimlik doğrulama akışlarında kullanabileceğiniz yöntemleri (örneğin, acquireTokenWithAuthorizationCode web uygulamaları için) kullanıma sunan bir AuthenticationContext nesne başlatırsınız. Başlatılırken, tek zorunlu parametre yetkili URI'dir:

var adal = require('adal-node');

var authorityURI = "https://login.microsoftonline.com/common";
var authenticationContex = new adal.AuthenticationContext(authorityURI);

MSAL Node'da bunun yerine iki alternatif vardır: Mobil uygulama veya masaüstü uygulaması oluşturuyorsanız bir nesne örneği oluşturursunuz PublicClientApplication . Oluşturucu en azından parametresini clientId içeren bir yapılandırma nesnesi bekler. Belirtmezseniz MSAL, yetkili URI'sini https://login.microsoftonline.com/common varsayılan olarak kullanır.

const msal = require('@azure/msal-node');

const pca = new msal.PublicClientApplication({
        auth: {
            clientId: "YOUR_CLIENT_ID"
        }
    });

Dekont

v2.0'da yetkiliyi https://login.microsoftonline.com/common kullanırsanız, kullanıcıların herhangi bir Microsoft Entra kuruluşuyla veya kişisel bir Microsoft hesabıyla (MSA) oturum açmasına izin verirsiniz. MSAL Node'da, herhangi bir Microsoft Entra hesabıyla (ADAL Düğümü ile aynı davranış) oturum açmayı kısıtlamak istiyorsanız, bunun yerine kullanın https://login.microsoftonline.com/organizations .

Öte yandan, bir web uygulaması veya daemon uygulaması oluşturuyorsanız bir ConfidentialClientApplication nesne örneği oluşturursunuz. Bu tür uygulamalarla istemci gizli dizisi veya sertifika gibi bir istemci kimlik bilgisi sağlamanız da gerekir:

const msal = require('@azure/msal-node');

const cca = new msal.ConfidentialClientApplication({
        auth: {
            clientId: "YOUR_CLIENT_ID",
            clientSecret: "YOUR_CLIENT_SECRET"
        }
    });

ADAL'ın AuthenticationContextaksine hem hem ConfidentialClientApplicationde PublicClientApplication , bir istemci kimliğine bağlıdır. Başka bir deyişle, uygulamanızda kullanmak istediğiniz farklı istemci kimlikleriniz varsa, her bir örnek için yeni bir MSAL örneği oluşturmanız gerekir. Daha fazla bilgi için bkz. MSAL Düğümünün Başlatılması

MSAL'yi yapılandırma

Microsoft kimlik platformu üzerinde uygulama oluştururken, uygulamanız kimlik doğrulamasıyla ilgili birçok parametre içerir. ADAL Düğümü'nde nesnenin AuthenticationContext örneği oluşturabileceğiniz sınırlı sayıda yapılandırma parametresi vardır, kalan parametreler ise kodunuzda serbestçe yanıtsız kalır (örneğin, clientSecret):

var adal = require('adal-node');

var authority = "https://login.microsoftonline.com/YOUR_TENANT_ID"
var validateAuthority = true,
var cache = null;

var authenticationContext = new adal.AuthenticationContext(authority, validateAuthority, cache);
  • authority: Belirteç yetkilisini tanımlayan URL
  • validateAuthority: Kodunuzun kötü amaçlı olabilecek bir yetkiliden belirteç istemesini engelleyen bir özellik
  • cache: bu AuthenticationContext örneği tarafından kullanılan belirteç önbelleğini ayarlar. Bu parametre ayarlı değilse, bellek önbelleğinde varsayılan bir değer kullanılır

Öte yandan MSAL Düğümü, Yapılandırma türünde bir yapılandırma nesnesi kullanır. Aşağıdaki özelliklerde oluşur:

const msal = require('@azure/msal-node');

const msalConfig = {
    auth: {
        clientId: "YOUR_CLIENT_ID",
        authority: "https://login.microsoftonline.com/YOUR_TENANT_ID",
        clientSecret: "YOUR_CLIENT_SECRET",
        knownAuthorities: [],
    },
    cache: {
        // your implementation of caching
    },
    system: {
        loggerOptions: { /** logging related options */ }
    }
}


const cca = new msal.ConfidentialClientApplication(msalConfig);

Önemli bir fark olarak, MSAL'nin yetkili doğrulamasını devre dışı bırakmak için bir bayrağı yoktur ve yetkililer her zaman varsayılan olarak doğrulanır. MSAL, istediğiniz yetkiyi Microsoft tarafından bilinen bir yetkili listesiyle veya yapılandırmanızda belirttiğiniz yetkili listesiyle karşılaştırır. Daha fazla bilgi için bkz. Yapılandırma Seçenekleri

MSAL API'sine geçiş yapma

ADAL Düğümündeki genel yöntemlerin çoğunun MSAL Düğümündeki eşdeğerleri vardır:

ADAL MSAL Notlar
acquireToken acquireTokenSilent Yeniden adlandırıldı ve şimdi bir hesap nesnesi bekliyor
acquireTokenWithAuthorizationCode acquireTokenByCode
acquireTokenWithClientCredentials acquireTokenByClientCredential
acquireTokenWithRefreshToken acquireTokenByRefreshToken Geçerli yenileme belirteçlerini geçirmek için kullanışlıdır
acquireTokenWithDeviceCode acquireTokenByDeviceCode Şimdi kullanıcı kodu alımını soyutlar (aşağıya bakın)
acquireTokenWithUsernamePassword acquireTokenByUsernamePassword

Ancak, MSAL Düğümü yeni yöntemler sunarken, ADAL Düğümündeki bazı yöntemler kullanım dışı bırakılmıştır:

ADAL MSAL Notlar
acquireUserCode Yok ile acquireTokeByDeviceCode birleştirildi (yukarıya bakın)
Yok acquireTokenOnBehalfOf OBO akışını soyutlayan yeni bir yöntem
acquireTokenWithClientCertificate Yok Şimdi başlatma sırasında sertifikalar atandığından artık gerekli değildir (bkz . yapılandırma seçenekleri)
Yok getAuthCodeUrl Yetkilendirme uç noktası URL'si oluşturmayı soyutlayan yeni bir yöntem

Kaynaklar yerine kapsamları kullanma

v1.0 ile v2.0 uç noktaları arasındaki önemli bir fark, kaynaklara nasıl erişildiğinden farklıdır. ADAL Düğümü'nde, önce uygulama kayıt portalına bir izin kaydeder ve ardından aşağıda gösterildiği gibi bir kaynak (Microsoft Graph gibi) için erişim belirteci isteyebilirsiniz:

authenticationContext.acquireTokenWithAuthorizationCode(
    req.query.code,
    redirectUri,
    resource, // e.g. 'https://graph.microsoft.com'
    clientId,
    clientSecret,
    function (err, response) {
        // do something with the authentication response
    }
);

MSAL Düğümü yalnızca v2.0 uç noktasını destekler. v2.0 uç noktası, kaynaklara erişmek için kapsam odaklı bir model kullanır. Bu nedenle, bir kaynak için erişim belirteci istediğinizde, bu kaynağın kapsamını da belirtmeniz gerekir:

const tokenRequest = {
    code: req.query.code,
    scopes: ["https://graph.microsoft.com/User.Read"],
    redirectUri: REDIRECT_URI,
};

pca.acquireTokenByCode(tokenRequest).then((response) => {
    // do something with the authentication response
}).catch((error) => {
    console.log(error);
});

Kapsam odaklı modelin avantajlarından biri dinamik kapsamları kullanabilmektir. v1.0 kullanarak uygulama oluştururken, kullanıcının oturum açma sırasında onay verebilmek için uygulamanın gerektirdiği tam izin kümesini (statik kapsamlar olarak adlandırılır) kaydetmeniz gerekiyordu. v2.0'da scope parametresini kullanarak izinleri istediğiniz anda isteyebilirsiniz (dolayısıyla dinamik kapsamlar). Bu, kullanıcının kapsamlara artımlı onay sağlamasına olanak tanır. Bu nedenle, başlangıçta yalnızca kullanıcının uygulamanızda oturum açmasını istiyorsanız ve herhangi bir erişime ihtiyacınız yoksa, bunu yapabilirsiniz. Daha sonra kullanıcının takvimini okuma yeteneğine ihtiyacınız varsa, acquireToken yöntemlerinde takvim kapsamını isteyebilir ve kullanıcının onayını alabilirsiniz. Daha fazla bilgi için bkz. Kaynaklar ve kapsamlar

Geri çağırmalar yerine promises kullanma

ADAL Düğümünde, kimlik doğrulaması başarılı olduktan ve bir yanıt alındıktan sonra geri çağırmalar herhangi bir işlem için kullanılır:

var context = new AuthenticationContext(authorityUrl, validateAuthority);

context.acquireTokenWithClientCredentials(resource, clientId, clientSecret, function(err, response) {
    if (err) {
        console.log(err);
    } else {
        // do something with the authentication response
    }
});

MSAL Düğümü'nde bunun yerine promise'ler kullanılır:

    const cca = new msal.ConfidentialClientApplication(msalConfig);

    cca.acquireTokenByClientCredential(tokenRequest).then((response) => {
        // do something with the authentication response
    }).catch((error) => {
        console.log(error);
    });

ES8 ile birlikte gelen zaman uyumsuz/await söz dizimini de kullanabilirsiniz:

    try {
        const authResponse = await cca.acquireTokenByCode(tokenRequest);
    } catch (error) {
        console.log(error);
    }

Günlü kaydını etkinleştir

ADAL Düğümü'nde, günlüğü kodunuzun herhangi bir yerinde ayrı olarak yapılandırabilirsiniz:

var adal = require('adal-node');

//PII or OII logging disabled. Default Logger does not capture any PII or OII.
adal.logging.setLoggingOptions({
  log: function (level, message, error) {
    console.log(message);

    if (error) {
        console.log(error);
    }
  },
  level: logging.LOGGING_LEVEL.VERBOSE, // provide the logging level
  loggingWithPII: false  // Determine if you want to log personal identification information. The default value is false.
});

MSAL Düğümü'nde günlük, yapılandırma seçeneklerinin bir parçasıdır ve MSAL Node örneğinin başlatılmasıyla oluşturulur:

const msal = require('@azure/msal-node');

const msalConfig = {
    auth: {
        // authentication related parameters
    },
    cache: {
        // cache related parameters
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: msal.LogLevel.Verbose,
        }
    }
}

const cca = new msal.ConfidentialClientApplication(msalConfig);

Belirteç önbelleğe almayı etkinleştirme

ADAL Düğümü'nde bellek içi belirteç önbelleğini içeri aktarma seçeneğiniz vardı. Belirteç önbelleği, bir AuthenticationContext nesne başlatılırken parametre olarak kullanılır:

var MemoryCache = require('adal-node/lib/memory-cache');

var cache = new MemoryCache();
var authorityURI = "https://login.microsoftonline.com/common";

var context = new AuthenticationContext(authorityURI, true, cache);

MSAL Düğümü varsayılan olarak bellek içi belirteç önbelleği kullanır. Açıkça içeri aktarmanız gerekmez; bellek içi belirteç önbelleği ve PublicClientApplication sınıflarının ConfidentialClientApplication bir parçası olarak kullanıma sunulur.

const msalTokenCache = publicClientApplication.getTokenCache();

Önemli olan, önbellek şemaları uyumsuz olduğundan ADAL Düğümü ile önceki belirteç önbelleğiniz MSAL Düğümüne aktarılamaz. Ancak, uygulamanızın daha önce MSAL Düğümü'nde ADAL Düğümü ile edinmiş olduğu geçerli yenileme belirteçlerini kullanabilirsiniz. Daha fazla bilgi için yenileme belirteçleri bölümüne bakın.

Ayrıca kendi önbellek eklentinizi sağlayarak önbelleğinizi diske yazabilirsiniz. Önbellek eklentisi arabirimini ICachePluginuygulamalıdır. Günlüğe kaydetme gibi önbelleğe alma da yapılandırma seçeneklerinin bir parçasıdır ve MSAL Node örneğinin başlatılmasıyla oluşturulur:

const msal = require('@azure/msal-node');

const msalConfig = {
    auth: {
        // authentication related parameters
    },
    cache: {
        cachePlugin // your implementation of cache plugin
    },
    system: {
        // logging related options
    }
}

const msalInstance = new ConfidentialClientApplication(msalConfig);

Aşağıdaki gibi örnek bir önbellek eklentisi uygulanabilir:

const fs = require('fs');

// Call back APIs which automatically write and read into a .json file - example implementation
const beforeCacheAccess = async (cacheContext) => {
    cacheContext.tokenCache.deserialize(await fs.readFile(cachePath, "utf-8"));
};

const afterCacheAccess = async (cacheContext) => {
    if(cacheContext.cacheHasChanged) {
        await fs.writeFile(cachePath, cacheContext.tokenCache.serialize());
    }
};

// Cache Plugin
const cachePlugin = {
    beforeCacheAccess,
    afterCacheAccess
};

Masaüstü uygulamaları gibi genel istemci uygulamaları geliştiriyorsanız, Node için Microsoft Authentication Extensions, istemci uygulamalarının platformlar arası belirteç önbelleği serileştirmesi ve kalıcılığı gerçekleştirmesi için güvenli mekanizmalar sunar. Desteklenen platformlar Windows, Mac ve Linux'tır.

Dekont

Ölçeklendirme ve performans sorunlarına neden olabileceği için, Web uygulamaları için Node için Microsoft Kimlik Doğrulama Uzantıları önerilmez. Bunun yerine, web uygulamalarının önbelleği oturumda kalıcı hale getirmek için kullanılması önerilir.

Yenileme belirteçlerinin etrafındaki mantığı kaldırma

ADAL Düğümü'nde yenileme belirteçleri (RT) kullanıma sunuldu ve bu belirteçleri önbelleğe alarak ve yöntemini kullanarak acquireTokenWithRefreshToken bu belirteçlerin kullanımına yönelik çözümler geliştirmenizi sağlar. RT'lerin özellikle ilgili olduğu tipik senaryolar:

  • Kullanıcıların artık bağlı olmadığı kullanıcılar adına panoları yenileme gibi eylemlerde bulunan uzun süre çalışan hizmetler.
  • İstemcinin RT'yi web hizmetine getirmesini sağlamak için WebFarm senaryoları (önbelleğe alma, sunucu tarafı değil istemci tarafı, şifrelenmiş tanımlama bilgisi yapılır).

MSAL Düğümü, diğer MSAL'lerle birlikte güvenlik nedeniyle yenileme belirteçlerini kullanıma sunmaz. Bunun yerine, MSAL sizin için yenileme belirteçlerini işler. Bu nedenle, artık bunun için mantık oluşturmanız gerekmez. Ancak, MSAL Node ile yeni bir belirteç kümesi almak için ADAL Düğümü önbelleğinden daha önce edindiğiniz (ve hala geçerli) yenileme belirteçlerinizi kullanabilirsiniz. Bunu yapmak için MSAL Node, ADAL Node'un acquireTokenWithRefreshToken yöntemine eşdeğer olan öğesini sunaracquireTokenByRefreshToken:

var msal = require('@azure/msal-node');

const config = {
    auth: {
        clientId: "ENTER_CLIENT_ID",
        authority: "https://login.microsoftonline.com/ENTER_TENANT_ID",
        clientSecret: "ENTER_CLIENT_SECRET"
    }
};

const cca = new msal.ConfidentialClientApplication(config);

const refreshTokenRequest = {
    refreshToken: "", // your previous refresh token here
    scopes: ["https://graph.microsoft.com/.default"],
    forceCache: true,
};

cca.acquireTokenByRefreshToken(refreshTokenRequest).then((response) => {
    console.log(response);
}).catch((error) => {
    console.log(error);
});

Daha fazla bilgi için lütfen ADAL Düğümünden MSAL Düğümüne geçiş örneğine bakın.

Dekont

Yukarıda gösterildiği gibi MSAL Node'un acquireTokenByRefreshToken yöntemini kullanarak yeni bir belirteç kümesi almak için hala geçerli yenileme belirteçlerini kullandıktan sonra eski ADAL Düğümü belirteç önbelleğini yok etmenizi öneririz.

Hataları ve özel durumları işleme

MSAL Düğümü kullanırken karşılaşabileceğiniz en yaygın hata türü hatadır interaction_required . Bu hata genellikle etkileşimli bir belirteç alma istemi başlatılarak çözülür. Örneğin, kullanırken acquireTokenSilentönbelleğe alınmış yenileme belirteci yoksa, MSAL Düğümü sessizce bir erişim belirteci alamaz. Benzer şekilde, erişmeye çalıştığınız web API'sinde de kullanıcının çok faktörlü kimlik doğrulaması (MFA) gerçekleştirmesini gerektiren bir Koşullu Erişim ilkesi olabilir. Bu gibi durumlarda, tetikleyerek acquireTokenByCode hatanın işlenmesi interaction_required kullanıcıdan MFA istemesine neden olur ve tam olarak sağlamasına olanak tanır.

Yine de, korumalı bir kaynak için erişim belirteci almak için gereken izinler kullanıcı tarafından onaylanmadığında oluşan bir diğer yaygın hatayla karşılaşabilirsiniz consent_required. içinde interaction_requiredolduğu gibi hatanın çözümü consent_required genellikle yöntemini kullanarak etkileşimli bir belirteç alma istemi başlatır acquireTokenByCode .

Uygulamayı çalıştırma

Değişiklikleriniz tamamlandıktan sonra uygulamayı çalıştırın ve kimlik doğrulama senaryonuzu test edin:

npm start

Örnek: ADAL Düğümü ve MSAL Düğümü ile belirteç alma

Aşağıdaki kod parçacığı Express.js çerçevesinde gizli bir istemci web uygulamasını gösterir. Kullanıcı kimlik doğrulama yoluna ulaştığında oturum açma işlemi gerçekleştirir, yol /authüzerinden /redirect Microsoft Graph için bir erişim belirteci alır ve ardından belirtilen belirtecin içeriğini görüntüler.

ADAL Düğümünü Kullanma MSAL Düğümünü Kullanma
// Import dependencies
var express = require('express');
var crypto = require('crypto');
var adal = require('adal-node');

// Authentication parameters
var clientId = 'Enter_the_Application_Id_Here';
var clientSecret = 'Enter_the_Client_Secret_Here';
var tenant = 'Enter_the_Tenant_Info_Here';
var authorityUrl = 'https://login.microsoftonline.com/' + tenant;
var redirectUri = 'http://localhost:3000/redirect';
var resource = 'https://graph.microsoft.com';

// Configure logging
adal.Logging.setLoggingOptions({
    log: function (level, message, error) {
        console.log(message);
    },
    level: adal.Logging.LOGGING_LEVEL.VERBOSE,
    loggingWithPII: false
});

// Auth code request URL template
var templateAuthzUrl = 'https://login.microsoftonline.com/'
    + tenant + '/oauth2/authorize?response_type=code&client_id='
    + clientId + '&redirect_uri=' + redirectUri
    + '&state=<state>&resource=' + resource;

// Initialize express
var app = express();

// State variable persists throughout the app lifetime
app.locals.state = "";

app.get('/auth', function(req, res) {

    // Create a random string to use against XSRF
    crypto.randomBytes(48, function(ex, buf) {
        app.locals.state = buf.toString('base64')
            .replace(/\//g, '_')
            .replace(/\+/g, '-');

        // Construct auth code request URL
        var authorizationUrl = templateAuthzUrl
            .replace('<state>', app.locals.state);

        res.redirect(authorizationUrl);
    });
});

app.get('/redirect', function(req, res) {
    // Compare state parameter against XSRF
    if (app.locals.state !== req.query.state) {
        res.send('error: state does not match');
    }

    // Initialize an AuthenticationContext object
    var authenticationContext =
        new adal.AuthenticationContext(authorityUrl);

    // Exchange auth code for tokens
    authenticationContext.acquireTokenWithAuthorizationCode(
        req.query.code,
        redirectUri,
        resource,
        clientId,
        clientSecret,
        function(err, response) {
            res.send(response);
        }
    );
});

app.listen(3000, function() {
    console.log(`listening on port 3000!`);
});
// Import dependencies
const express = require("express");
const msal = require('@azure/msal-node');

// Authentication parameters
const config = {
    auth: {
        clientId: "Enter_the_Application_Id_Here",
        authority: "https://login.microsoftonline.com/Enter_the_Tenant_Info_Here",
        clientSecret: "Enter_the_Client_Secret_Here"
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: msal.LogLevel.Verbose,
        }
    }
};

const REDIRECT_URI = "http://localhost:3000/redirect";

// Initialize MSAL Node object using authentication parameters
const cca = new msal.ConfidentialClientApplication(config);

// Initialize express
const app = express();

app.get('/auth', (req, res) => {

    // Construct a request object for auth code
    const authCodeUrlParameters = {
        scopes: ["user.read"],
        redirectUri: REDIRECT_URI,
    };

    // Request auth code, then redirect
    cca.getAuthCodeUrl(authCodeUrlParameters)
        .then((response) => {
            res.redirect(response);
        }).catch((error) => res.send(error));
});

app.get('/redirect', (req, res) => {

    // Use the auth code in redirect request to construct
    // a token request object
    const tokenRequest = {
        code: req.query.code,
        scopes: ["user.read"],
        redirectUri: REDIRECT_URI,
    };

    // Exchange the auth code for tokens
    cca.acquireTokenByCode(tokenRequest)
        .then((response) => {
            res.send(response);
        }).catch((error) => res.status(500).send(error));
});

app.listen(3000, () =>
    console.log(`listening on port 3000!`));

Sonraki adımlar