Bagikan melalui


Cara memigrasikan aplikasi Node.js dari ADAL ke MSAL

Microsoft Authentication Library for Node (MSAL Node) sekarang menjadi SDK yang direkomendasikan untuk mengaktifkan autentikasi dan otorisasi untuk aplikasi Anda yang terdaftar di platform identitas Microsoft. Artikel ini membahas langkah-langkah penting yang perlu Anda lalui untuk memigrasikan aplikasi Anda dari Active Directory Authentication Library for Node (ADAL Node) ke MSAL Node.

Prasyarat

Memperbarui pengaturan pendaftaran aplikasi

Saat bekerja dengan ADAL Node, Anda mungkin menggunakan titik akhir Microsoft Azure Active Directory v1.0. Aplikasi yang bermigrasi dari ADAL ke MSAL harus beralih ke titik akhir Azure AD v2.0.

Menginstal dan mengimpor MSAL

  1. instal paket MSAL Node melalui npm:
  npm install @azure/msal-node
  1. Setelah itu, impor MSAL Node dalam kode Anda:
  const msal = require('@azure/msal-node');
  1. Terakhir, hapus instalan paket ADAL Node dan hapus referensi apa pun dalam kode Anda:
  npm uninstall adal-node

Menginisialisasi MSAL

Di ADAL Node, Anda menginisialisasi AuthenticationContext objek, yang kemudian mengekspos metode yang dapat Anda gunakan dalam alur autentikasi yang berbeda (misalnya, acquireTokenWithAuthorizationCode untuk aplikasi web). Saat menginisialisasi, satu-satunya parameter wajib adalah URI otoritas:

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

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

Di MSAL Node, Anda memiliki dua alternatif sebagai gantinya: Jika Anda membangun aplikasi seluler atau aplikasi desktop, Anda membuat PublicClientApplication instans objek. Konstruktor mengharapkan objek konfigurasi yang berisi setidaknya parameter clientId. MSAL mengatur default URI otoritas jika https://login.microsoftonline.com/common Anda tidak menentukannya.

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

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

Catatan

Jika Anda menggunakan https://login.microsoftonline.com/common otoritas di v2.0, Anda akan mengizinkan pengguna untuk masuk dengan organisasi Microsoft Entra atau akun Microsoft pribadi (MSA). Di MSAL Node, jika Anda ingin membatasi login ke akun Microsoft Entra apa pun (perilaku yang sama seperti dengan ADAL Node), gunakan https://login.microsoftonline.com/organizations sebagai gantinya.

Di sisi lain, jika Anda membuat aplikasi web atau aplikasi daemon, Anda membuat ConfidentialClientApplication instans objek. Dengan aplikasi tersebut, Anda juga perlu menyediakan kredensial klien, seperti rahasia klien atau sertifikat:

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

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

PublicClientApplication dan ConfidentialClientApplication, tidak seperti AuthenticationContext ADAL, terikat ke ID klien. Artinya jika Anda memiliki ID klien yang berbeda yang ingin Anda gunakan dalam aplikasi Anda, Anda perlu membuat contoh instans MSAL baru untuk masing-masing. Lihat lebih lanjut: Menginisialisasi MSAL Node

Mengonfigurasi MSAL

Saat membangun aplikasi di platform identitas Microsoft, aplikasi Anda akan berisi banyak parameter yang terkait dengan autentikasi. Di ADAL Node, AuthenticationContext objek memiliki sejumlah parameter konfigurasi terbatas yang dapat Anda buat, sementara parameter yang tersisa menggantung dengan bebas dalam kode Anda (misalnya, 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: URL yang mengidentifikasi otoritas token
  • validateAuthority: fitur yang mencegah kode Anda meminta token dari otoritas yang berpotensi berbahaya
  • cache: menetapkan cache token yang digunakan oleh instans AuthenticationContext ini. Jika parameter ini tidak diatur, maka default, dalam cache memori digunakan

MSAL Node di sisi lain menggunakan objek konfigurasi jenis Konfigurasi. Berisi properti berikut:

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

Sebagai perbedaan penting, MSAL tidak memiliki bendera untuk menonaktifkan validasi otoritas dan otoritas selalu divalidasi secara default. MSAL membandingkan otoritas yang Anda minta dengan daftar otoritas yang diketahui oleh Microsoft atau daftar otoritas yang Anda tentukan dalam konfigurasi Anda. Lihat untuk informasi selengkapnya: Opsi Konfigurasi

Beralih ke API MSAL

Sebagian besar metode publik di ADAL Node memiliki ekuivalen di MSAL Node:

ADAL MSAL Catatan
acquireToken acquireTokenSilent Berganti nama dan sekarang mengharapkan objek akun
acquireTokenWithAuthorizationCode acquireTokenByCode
acquireTokenWithClientCredentials acquireTokenByClientCredential
acquireTokenWithRefreshToken acquireTokenByRefreshToken Berguna untuk memigrasikan token penyegaran yang valid
acquireTokenWithDeviceCode acquireTokenByDeviceCode Sekarang mengabstraksi akuisisi kode pengguna (lihat di bawah)
acquireTokenWithUsernamePassword acquireTokenByUsernamePassword

Namun, beberapa metode dalam ADAL Node ditolak, sewaktu MSAL Node menawarkan metode baru:

ADAL MSAL Catatan
acquireUserCode T/A Digabungkan dengan acquireTokeByDeviceCode (lihat di atas)
T/A acquireTokenOnBehalfOf Metode baru yang mengabstraksi alur OBO
acquireTokenWithClientCertificate T/A Tidak lagi diperlukan karena sertifikat ditetapkan selama inisialisasi saat ini (lihat opsi konfigurasi)
T/A getAuthCodeUrl Metode baru yang mengabstraksi mengotorisasi konstruksi URL titik akhir

Menggunakan cakupan sebagai ganti sumber daya

Perbedaan penting antara titik akhir v1.0 vs. v2.0 adalah tentang cara akses sumber daya. Di ADAL Node, Anda pertama-tama akan mendaftarkan izin di portal pendaftaran aplikasi, lalu meminta token akses untuk sumber daya (seperti Microsoft Graph) seperti yang ditunjukkan di bawah ini:

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 Node hanya mendukung titik akhir v2.0 . Titik akhir v2.0 menggunakan model yang berpusat pada cakupan untuk mengakses sumber daya. Jadi, ketika Anda meminta token akses untuk sumber daya, Anda juga perlu menentukan cakupan untuk sumber daya tersebut:

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

Salah satu manfaat dari model yang berpusat pada cakupan adalah kemampuan untuk menggunakan cakupan dinamis. Saat membangun aplikasi menggunakan v1.0, Anda harus mendaftarkan sekumpulan izin lengkap (yang disebut cakupan statis) yang diperlukan aplikasi untuk disetujui pengguna pada saat masuk. Di v2.0, Anda dapat menggunakan parameter cakupan untuk meminta izin pada waktu yang Anda inginkan (oleh karena itu, cakupan dinamis). Ini memungkinkan pengguna memberikan persetujuan bertahap untuk cakupan. Jadi, jika pada awalnya Anda hanya ingin pengguna masuk ke aplikasi Anda dan Anda tidak memerlukan akses apa pun, Anda dapat melakukannya. Jika nantinya Anda memerlukan kemampuan untuk membaca kalender pengguna, Anda selanjutnya dapat meminta cakupan kalender dalam metode acquireToken dan mendapatkan persetujuan pengguna. Lihat untuk informasi selengkapnya: Sumber daya dan cakupan

Menggunakan janji sebagai ganti panggilan balik

Di ADAL Node, panggilan balik digunakan untuk operasi apa pun setelah otentikasi berhasil dan respons diperoleh:

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

Di MSAL Node, janji digunakan sebagai gantinya:

    const cca = new msal.ConfidentialClientApplication(msalConfig);

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

Anda juga dapat menggunakan sintaks async/await yang disertakan dengan ES8:

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

Aktifkan pencatatan log

Di ADAL Node, Anda mengonfigurasi pengelogan secara terpisah di mana saja dalam kode Anda:

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

Di MSAL Node, pengelogan adalah bagian dari opsi konfigurasi dan dibuat dengan inisialisasi instans MSAL Node:

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

Mengaktifkan penembolokan token

Di ADAL Node, Anda memiliki opsi untuk mengimpor cache token dalam memori. Cache token digunakan sebagai parameter saat menginisialisasi objek AuthenticationContext:

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 Node menggunakan cache token dalam memori secara default. Anda tidak perlu mengimpornya secara eksplisit; cache token dalam memori diekspos sebagai bagian ConfidentialClientApplication dari kelas dan PublicClientApplication .

const msalTokenCache = publicClientApplication.getTokenCache();

Yang penting, cache token Anda sebelumnya dengan ADAL Node tidak akan dapat ditransfer ke MSAL Node, karena skema cache tidak kompatibel. Namun, Anda dapat menggunakan token refresh valid yang diperoleh aplikasi Anda sebelumnya dengan ADAL Node di MSAL Node. Lihat bagian tentang refresh token untuk informasi selengkapnya.

Anda juga dapat menulis cache Anda ke disk dengan menyediakan plugin cache Anda sendiri. Plugin cache harus mengimplementasikan antarmuka ICachePlugin. Seperti pengelogan, caching adalah bagian dari opsi konfigurasi dan dibuat dengan inisialisasi instans MSAL Node:

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

Contoh plugin cache dapat diimplementasikan seperti di bawah ini:

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

Jika Anda mengembangkan aplikasi klien publik seperti aplikasi desktop, Microsoft Authentication Extensions for Node menawarkan mekanisme yang aman bagi aplikasi klien untuk melakukan serialisasi dan persistensi cache token lintas platform. Platform yang didukung adalah Windows, Mac, dan Linux.

Catatan

Microsoft Authentication Extensions for Nodetidak direkomendasikan untuk aplikasi web, karena dapat menyebabkan masalah skala dan performa. Sebagai gantinya, aplikasi web direkomendasikan untuk menyimpan cache dalam sesi.

Menghapus logika di sekitar token refresh

Di ADAL Node, token refresh (RT) diekspos yang memungkinkan Anda mengembangkan solusi seputar penggunaan token ini dengan men-cache token dan menggunakan metode acquireTokenWithRefreshToken. Skenario umum ketika RT sangat relevan:

  • Layanan jangka panjang yang menjalankan tindakan termasuk me-refresh dasbor atas nama pengguna ketika pengguna tidak lagi terhubung.
  • Skenario WebFarm untuk memungkinkan klien membawa RT ke layanan web (caching dilakukan di sisi klien, cookie terenkripsi, dan bukan sisi server).

MSAL Node, bersama dengan MSAL lainnya, tidak mengekspos token refresh karena alasan keamanan. Sebagai gantinya, MSAL menangani token refreshing untuk Anda. Dengan demikian, Anda tidak perlu lagi membangun logika untuk ini. Namun, Anda dapat menggunakan token penyegaran yang diperoleh sebelumnya (dan masih valid) dari cache ADAL Node untuk mendapatkan set token baru dengan MSAL Node. Untuk melakukan ini, MSAL Node menawarkan acquireTokenByRefreshToken, yang setara dengan metode acquireTokenWithRefreshToken ADAL Node:

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

Untuk informasi lebih lanjut, lihat sampel migrasi Node ADAL ke Node MSAL.

Catatan

Kami menyarankan Anda untuk menghancurkan cache token ADAL Node lama setelah Anda menggunakan token penyegaran yang masih valid untuk mendapatkan set token baru menggunakan metode acquireTokenByRefreshToken MSAL Node seperti yang ditunjukkan di atas.

Menangani kesalahan umum dan pengecualian

Saat menggunakan MSAL Node, jenis kesalahan paling umum yang mungkin Anda hadapi adalah kesalahan interaction_required. Kesalahan ini sering diatasi dengan memulai permintaan akuisisi token interaktif. Misalnya, saat menggunakan acquireTokenSilent, jika tidak ada token refresh yang di-cache, MSAL Node tidak akan dapat memperoleh token akses secara diam-diam. Demikian pula, API web yang coba Anda akses mungkin memiliki kebijakan Akses Bersyarat, mengharuskan pengguna untuk melakukan autentikasi multifaktor (MFA). Dalam kasus seperti itu, menangani kesalahan interaction_required dengan memicu acquireTokenByCode akan meminta pengguna untuk MFA, memungkinkan mereka untuk memenuhinya.

Namun kesalahan umum lain yang mungkin Anda hadapi adalah consent_required, yang terjadi ketika izin yang diperlukan untuk mendapatkan token akses untuk sumber daya yang dilindungi tidak disetujui oleh pengguna. Seperti pada interaction_required, solusi untuk kesalahan consent_required sering kali memulai permintaan akuisisi token interaktif, menggunakan metode acquireTokenByCode.

Menjalankan aplikasi

Setelah perubahan selesai, jalankan aplikasi dan uji skenario autentikasi Anda:

npm start

Contoh: Memperoleh token dengan ADAL Node vs. MSAL Node

Cuplikan di bawah ini menunjukkan aplikasi web klien rahasia dalam kerangka kerja Express.js. Masuk dijalankan ketika pengguna mencapai rute otentikasi /auth, memperoleh token akses untuk Microsoft Graph melalui rute /redirect, lalu menampilkan konten token tersebut.

Menggunakan Simpul ADAL Menggunakan Node MSAL
// 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!`));

Langkah berikutnya