如何將 Node.js 應用程式從 ADAL 遷移至 MSAL
適用於節點的 Microsoft 驗證連結庫 (MSAL Node) 現在是建議的 SDK,可在 Microsoft 身分識別平台 上註冊的應用程式啟用驗證和授權。 本文涵蓋您需要執行的重要步驟,以便將應用程式從適用於節點的 Active Directory 驗證連結庫(ADAL 節點)移轉至 MSAL 節點。
必要條件
- 節點版本 10、12、14、16 或 18。 請參閱版本支援的附註
更新應用程式註冊設定
使用 ADAL 節點時,您可能會使用 Azure AD v1.0 端點。 從 ADAL 移轉至 MSAL 的應用程式應該切換至 Azure AD v2.0 端點。
安裝和匯入 MSAL
- 透過 npm 安裝 MSAL 節點套件:
npm install @azure/msal-node
- 之後,請在您的程式代碼中匯入 MSAL 節點:
const msal = require('@azure/msal-node');
- 最後,卸載 ADAL 節點套件,並移除程式代碼中的任何參考:
npm uninstall adal-node
初始化 MSAL
在ADAL Node中,您會初始化 AuthenticationContext
物件,然後公開可用於不同驗證流程的方法(例如Web acquireTokenWithAuthorizationCode
應用程式)。 初始化時,唯一的必要參數是 授權單位 URI:
var adal = require('adal-node');
var authorityURI = "https://login.microsoftonline.com/common";
var authenticationContex = new adal.AuthenticationContext(authorityURI);
在 MSAL Node 中,您有兩個替代方式:如果您要建置行動應用程式或傳統型應用程式,您可以具現化 PublicClientApplication
物件。 建構函式預期至少包含 參數的clientId
組態物件。 如果您未指定,MSAL 會將授權單位 URI https://login.microsoftonline.com/common
預設為 。
const msal = require('@azure/msal-node');
const pca = new msal.PublicClientApplication({
auth: {
clientId: "YOUR_CLIENT_ID"
}
});
注意
如果您在 v2.0 中使用 https://login.microsoftonline.com/common
授權單位,將允許使用者使用任何 Microsoft Entra 組織或個人 Microsoft 帳戶 (MSA) 登入。 在 MSAL 節點中,如果您想要限制登入任何 Microsoft Entra 帳戶(與 ADAL 節點的行為相同),請改用 https://login.microsoftonline.com/organizations
。
另一方面,如果您要建置 Web 應用程式或精靈應用程式,您會具現化 ConfidentialClientApplication
物件。 使用這類應用程式時,您也需要提供 客戶端認證,例如客戶端密碼或憑證:
const msal = require('@azure/msal-node');
const cca = new msal.ConfidentialClientApplication({
auth: {
clientId: "YOUR_CLIENT_ID",
clientSecret: "YOUR_CLIENT_SECRET"
}
});
PublicClientApplication
和ConfidentialClientApplication
與 ADAL 不同的AuthenticationContext
是,系結至用戶端識別碼。 這表示,如果您有想要在應用程式中使用的不同用戶端標識符,則必須為每個實例具現化新的 MSAL 實例。 如需詳細資訊,請參閱: MSAL 節點的初始化
設定 MSAL
在 Microsoft 身分識別平台 上建置應用程式時,您的應用程式會包含許多與驗證相關的參數。 在 ADAL Node 中 AuthenticationContext
,物件具有有限的組態參數數目,您可以將其具現化,而其餘參數會在程式碼中自由停止回應(例如 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
:識別令牌授權單位的 URLvalidateAuthority
:防止程式代碼向潛在惡意授權單位要求令牌的功能cache
:設定這個 AuthenticationContext 實例所使用的令牌快取。 如果未設定此參數,則會使用記憶體快取中的預設值
另一方面,MSAL 節點會使用 Configuration 類型的 組態物件。 它包含下列屬性:
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);
在顯著差異中,MSAL 沒有停用授權單位驗證的旗標,且依預設一律會驗證授權單位。 MSAL 會將您要求的授權單位與 Microsoft 已知的授權單位清單或您在設定中指定的授權單位清單進行比較。 如需詳細資訊,請參閱: 組態選項
切換至 MSAL API
ADAL Node 中的大部分公用方法在 MSAL 節點中具有對等專案:
ADAL | MSAL | 備註 |
---|---|---|
acquireToken |
acquireTokenSilent |
已重新命名,現在需要 帳戶 物件 |
acquireTokenWithAuthorizationCode |
acquireTokenByCode |
|
acquireTokenWithClientCredentials |
acquireTokenByClientCredential |
|
acquireTokenWithRefreshToken |
acquireTokenByRefreshToken |
適用於移轉有效的 重新整理令牌 |
acquireTokenWithDeviceCode |
acquireTokenByDeviceCode |
現在將使用者程式代碼擷取抽象化(請參閱下方) |
acquireTokenWithUsernamePassword |
acquireTokenByUsernamePassword |
不過,ADAL 節點中的某些方法已被取代,而 MSAL Node 則提供新的方法:
ADAL | MSAL | 備註 |
---|---|---|
acquireUserCode |
N/A | 與合併 acquireTokeByDeviceCode (請參閱上圖) |
N/A | acquireTokenOnBehalfOf |
抽象 OBO 流程的新方法 |
acquireTokenWithClientCertificate |
N/A | 在初始化期間不再需要憑證(請參閱 組態選項) |
N/A | getAuthCodeUrl |
抽象化端點 URL 建構的新方法 |
使用範圍而非資源
v1.0 與 v2.0 端點之間的重要差異在於如何存取資源。 在ADAL節點中,您會先在應用程式註冊入口網站上註冊許可權,然後要求資源的存取令牌(例如 Microsoft Graph),如下所示:
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 節點僅 支援 v2.0 端點。 v2.0 端點會 採用以範圍為中心的 模型來存取資源。 因此,當您要求資源的存取令牌時,您也需要指定該資源的範圍:
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);
});
以範圍為中心的模型的優點之一是能夠使用 動態範圍。 使用 v1.0 建置應用程式時,您必須註冊應用程式所需的完整許可權集(稱為 靜態範圍),讓使用者在登入時同意。 在 v2.0 中,您可以使用 scope 參數在您想要的許可權時要求許可權(因此, 動態範圍)。 這可讓使用者對範圍提供 累加同意 。 因此,如果一開始您只想讓使用者登入您的應用程式,而且您不需要任何類型的存取權,您可以這麼做。 如果您稍後需要能夠讀取使用者的行事曆,您可以接著在 acquireToken 方法中要求行事曆範圍,並取得使用者的同意。 如需詳細資訊,請參閱: 資源和範圍
使用承諾而不是回呼
在ADAL節點中,回呼會在驗證成功且取得響應之後用於任何作業:
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 節點中,會改用承諾:
const cca = new msal.ConfidentialClientApplication(msalConfig);
cca.acquireTokenByClientCredential(tokenRequest).then((response) => {
// do something with the authentication response
}).catch((error) => {
console.log(error);
});
您也可以使用 ES8 隨附的 async/await 語法:
try {
const authResponse = await cca.acquireTokenByCode(tokenRequest);
} catch (error) {
console.log(error);
}
啟用 記錄
在 ADAL 節點中,您會在程式碼的任何位置分別設定記錄:
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 節點中,記錄是組態選項的一部分,並使用 MSAL 節點實例的初始化建立:
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);
啟用令牌快取
在 ADAL 節點中,您可以選擇匯入記憶體內部令牌快取。 初始化物件時 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 節點預設會使用記憶體內部令牌快取。 您不需要明確匯入它;記憶體內部令牌快取會公開為 和 PublicClientApplication
類別的ConfidentialClientApplication
一部分。
const msalTokenCache = publicClientApplication.getTokenCache();
重要的是,使用 ADAL 節點的先前令牌快取無法傳輸至 MSAL 節點,因為快取架構不相容。 不過,您可以使用應用程式先前在 MSAL 節點中透過 ADAL 節點取得的有效重新整理令牌。 如需詳細資訊,請參閱重新整理令牌一節。
您也可以提供自己的 快取外掛程式,將快取寫入磁碟。 快取外掛程式必須實作 介面 ICachePlugin
。 就像記錄一樣,快取是組態選項的一部分,而且是使用 MSAL 節點實例的初始化所建立:
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);
範例快取外掛程式可以實作如下:
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
};
如果您要開發像是傳統型應用程式的公用用戶端應用程式,適用於 Node 的 Microsoft 驗證延伸模組會提供安全的機制,讓用戶端應用程式執行跨平臺令牌快取串行化和持續性。 支持的平臺包括 Windows、Mac 和 Linux。
注意
Web 應用程式不建議使用適用於 Node 的 Microsoft 驗證延伸模組,因為這可能會導致調整和效能問題。 相反地,建議使用 Web 應用程式在工作階段中保存快取。
拿掉重新整理令牌的邏輯
在ADAL節點中,重新整理令牌 (RT) 已公開,可讓您藉由快取這些令牌並使用方法,來開發使用這些 acquireTokenWithRefreshToken
令牌的解決方案。 RT 特別相關的一般案例:
- 長時間執行的服務會執行動作,包括代表使用者不再連線的使用者重新整理儀錶板。
- 可讓用戶端將 RT 帶入 Web 服務的 WebFarm 案例(快取已完成用戶端、加密的 Cookie,而不是伺服器端)。
MSAL 節點與其他 MSAL 不會基於安全性考慮而公開重新整理令牌。 相反地,MSAL 會為您處理重新整理令牌。 因此,您不再需要為此建置邏輯。 不過,您可以使用先前從 ADAL 節點快取取得的 (仍然有效) 重新整理令牌,以使用 MSAL Node 取得一組新的令牌。 若要這樣做,MSAL Node 提供 acquireTokenByRefreshToken
,這相當於 ADAL Node 的 acquireTokenWithRefreshToken
方法:
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);
});
如需詳細資訊,請參閱 ADAL節點至 MSAL 節點移轉範例。
注意
建議您在使用仍然有效的重新整理令牌,使用 MSAL Node 的 acquireTokenByRefreshToken
方法取得一組新的令牌,如上所示,建議您終結較舊的 ADAL 節點令牌快取。
處理錯誤和例外狀況
使用 MSAL 節點時,最常見的錯誤類型是 interaction_required
錯誤。 這個錯誤通常是藉由起始互動式令牌取得提示來解決。 例如,使用 acquireTokenSilent
時,如果沒有快取的重新整理令牌,MSAL 節點將無法以無訊息方式取得存取令牌。 同樣地,您嘗試存取的 Web API 可能會有 條件式存取 原則,要求使用者執行 多重要素驗證 (MFA)。 在這種情況下,藉由觸發acquireTokenByCode
處理interaction_required
錯誤會提示使用者輸入 MFA,讓他們能夠完整處理它。
然而,您可能會遇到的另一個常見錯誤是 consent_required
,當使用者未同意取得受保護資源存取令牌所需的許可權時,就會發生這種情況。 如同 在 中 interaction_required
,錯誤的解決方案 consent_required
通常會使用 acquireTokenByCode
方法起始互動式令牌取得提示。
執行應用程式
變更完成後,請執行應用程式並測試您的驗證案例:
npm start
範例:使用 ADAL 節點與 MSAL 節點取得令牌
下列代碼段示範 Express.js 架構中的機密用戶端應用程式。 當使用者叫用驗證路由 /auth
時,它會執行登入,透過 /redirect
路由取得 Microsoft Graph 的存取令牌,然後顯示上述令牌的內容。
使用 ADAL 節點 | 使用 MSAL 節點 |
|
|