問題描述
在前兩篇博文中,對NodeJS Express應(yīng)用 使用MSAL + AAD實現(xiàn)用戶登錄并獲取用戶信息督赤,獲取Authorization信息 ( ID Token, Access Token).
- 【Azure 應(yīng)用服務(wù)】NodeJS Express + MSAL 應(yīng)用實現(xiàn)AAD集成登錄并部署在App Service Linux環(huán)境中的實現(xiàn)步驟
- 【Azure 應(yīng)用服務(wù)】NodeJS Express + MSAL 應(yīng)用實現(xiàn)AAD登錄并獲取AccessToken -- cca.acquireTokenByCode(tokenRequest)
而在當(dāng)前這篇博文中瘸味,我們將會實現(xiàn)以下目的:
1)為NodeJS API應(yīng)用配置Bearer Token驗證組件 passport 和 passport-azure-ad
2)實現(xiàn)使用idToken驗證并訪問API
實現(xiàn)步驟
在完成Azure AD中的注冊應(yīng)用配置后,并且根據(jù)博文“ NodeJS Express + MSAL 應(yīng)用實現(xiàn)AAD登錄并獲取AccessToken -- cca.acquireTokenByCode(tokenRequest): https://www.cnblogs.com/lulight/p/16357246.html” 完成用戶登錄的前端應(yīng)用够挂,
參考官方示例 “Enable authentication in your own Node.js web API by using Azure Active Directory B2C : https://docs.microsoft.com/en-us/azure/active-directory-b2c/enable-authentication-in-node-web-app-with-api” 準備API端的代碼。
第一步:下載示例代碼
git clone https://github.com/Azure-Samples/active-directory-b2c-javascript-nodejs-webapi.git
Install app dependencies
cd active-directory-b2c-javascript-nodejs-webapi
npm install
npm update
下載后的文件結(jié)構(gòu)為:
第二步:修改config.json 文件和index.js中的 identityMetadata 值
options中即為 BearerStrategy的配置參數(shù)藕夫,因為當(dāng)前不適用AAD B2C孽糖,而是直接使用AAD,所以isB2C就需要設(shè)置為false毅贮,
const options = {
identityMetadata: 'https://login.partner.microsoftonline.cn/xxxxxxxx-66d7-xxxx-8f9f-xxxxxxxxxxxx/v2.0/.well-known/openid-configuration',
clientID: ##clientID,
audience: ##clientID, validateIssuer: true,
loggingLevel: 'info',
passReqToCallback: false
}
因為參考文檔中使用的試AAD B2C來認證Token办悟,而本示例中使用的是AAD來認證Token,所以很多參數(shù)配置有一點差別滩褥。
本次實驗中使用的參數(shù)說明如下:
-
identityMetadata
(必須字段):填寫進行OAuth 2.0 認證的 Openid-configuration地址病蛉,如在中國區(qū)的地址為 'https://login.partner.microsoftonline.cn/<your tenant id>/v2.0/.well-known/openid-configuration' - **
clientID
(必須字段): **為AAD中注冊應(yīng)用的Application ID - audience(可選):為一個字符串或者字符串?dāng)?shù)組,默認值為注冊應(yīng)用的Client ID
- validateIssuer(可選):如果不需要驗證Issuer這個參數(shù),需要設(shè)置為false铺然。默認值為true俗孝。當(dāng)使用AAD的Openid-configuration信息,它會通過identitymetadata中獲取 issuer信息
- loggingLevel(可選):AAD Validation 的日志輸出級別魄健,有info赋铝,error,warn可供設(shè)置
- passReqToCallback(可選):默認值為false沽瘦,用戶當(dāng)請求的第一個參數(shù)中提供了驗證函數(shù)時革骨,需要設(shè)置為true
關(guān)于BearerStrategy參數(shù)更多詳細說明請參考鏈接:https://github.com/AzureAD/passport-azure-ad#42-bearerstrategy
第三步:訪問API接口(/hello 需要Authorization, /public 不需要Authorization)
在index.js代碼中析恋,實現(xiàn)了兩個接口 /hello 和 /public良哲。 /hello 接口添加了passport.authenticate認證,訪問需要攜帶Authorization (JWT Token)助隧,而/public則無需認證筑凫。
//<ms_docref_protected_api_endpoint>
// API endpoint, one must present a bearer accessToken to access this endpoint
app.get('/hello',
passport.authenticate('oauth-bearer', {session: false}),
(req, res) => {
console.log(req.headers.authorization);
console.log('Validated claims: ', req.authInfo); // Service relies on the name claim.
res.status(200).json({'name': req.authInfo['name']});
}
);
//</ms_docref_protected_api_endpoint>
//<ms_docref_anonymous_api_endpoint>
// API anonymous endpoint, returns a date to the caller.
app.get('/public', (req, res) => res.send( {'date': new Date() } ));
//</ms_docref_anonymous_api_endpoint>
驗證效果:
第四步:驗證 idToken 和 accessToken
在前端UI頁面通過登錄后獲取到Token信息, http://localhost:3000/auth
驗證展示動畫:
使用accessTokne的錯誤日志
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"In Strategy.prototype.authenticate: received metadata","time":"2022-06-11T06:15:43.024Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"In Strategy.prototype.authenticate: we will validate the options","time":"2022-06-11T06:15:43.025Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"In Strategy.prototype.authenticate: access_token is received from request header","time":"2022-06-11T06:15:43.025Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"In Strategy.prototype.jwtVerify: token is decoded","time":"2022-06-11T06:15:43.027Z","v":0}
{"name":"AzureAD: Metadata Parser","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"working on key","time":"2022-06-11T06:15:43.028Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"PEMkey generated","time":"2022-06-11T06:15:43.033Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"authentication failed due to: In Strategy.prototype.jwtVerify: cannot verify token","time":"2022-06-11T06:15:43.036Z","v":0}
GET /hello 401 1.556 ms - -
使用idToken的正確日志
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"In Strategy.prototype.authenticate: received metadata","time":"2022-06-11T06:16:25.102Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"In Strategy.prototype.authenticate: we will validate the options","time":"2022-06-11T06:16:25.102Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"In Strategy.prototype.authenticate: access_token is received from request header","time":"2022-06-11T06:16:25.103Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"In Strategy.prototype.jwtVerify: token is decoded","time":"2022-06-11T06:16:25.104Z","v":0}
{"name":"AzureAD: Metadata Parser","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"working on key","time":"2022-06-11T06:16:25.104Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"PEMkey generated","time":"2022-06-11T06:16:25.105Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"In Strategy.prototype.jwtVerify: token is verified","time":"2022-06-11T06:16:25.107Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"MININT-S4MGVOU","pid":17316,"level":30,"msg":"In Strategy.prototype.jwtVerify: We did not pass Req back to Callback","time":"2022-06-11T06:16:25.107Z","v":0}
Validated claims: {
aud: 'xxxxx-c6fd-xxx-9dac-xxxxxx',
iss: 'https://login.partner.microsoftonline.cn/xxxxx-c6fd-xxx-9dac-xxxxxx/v2.0',
iat: 1654924192,
nbf: 1654924192,
exp: 1654928092,
name: 'your name here',
oid: 'xxxxx-c6fd-xxx-9dac-xxxxxx',
preferred_username: 'xxxx@xxxx.partner.onmschina.cn',
rh: '0.xxxxxxxxx-xxxxxxxxxxxxxx.',
sub: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
tid: 'x-66d7-47a8-xx-xxx',
uti: 'xxxxxxxxxxxxxxxxxxxxxxxxx',
ver: '2.0' }
GET /hello 200 11.557 ms - 16
[可選]第五步:修改AAD注冊應(yīng)用的accessTokenAcceptedVersion
因為中國區(qū)AAD目前生成的Token為OAuth v1.0喇颁, 而在API應(yīng)用中 identityMetadata 使用的是v2.0的openid-configration漏健。所以需要在ADD中修改當(dāng)前注冊應(yīng)用的清單文件(Mainfest)中
accessTokenAcceptedVersion 值為 2
- 登錄Azure 門戶,選擇Azure AD橘霎。
- 點擊 App registrations 并選擇自己的應(yīng)用蔫浆,如本示例中的“ExpressWebApp”
- 進入應(yīng)用Overview頁面后,選擇左側(cè)導(dǎo)航中“Manifest”清單頁面姐叁。修改 accessTokenAcceptedVersion 的值為2瓦盛,保存即可。
參考資料
Configure authentication in a sample Node.js web API by using Azure Active Directory B2C: https://docs.microsoft.com/en-us/azure/active-directory-b2c/configure-authentication-in-sample-node-web-app-with-api#step-4-get-the-web-api-sample-code
Microsoft Azure Active Directory Passport.js Plug-In:https://github.com/AzureAD/passport-azure-ad#42-bearerstrategy
Tutorial: Sign in users and acquire a token for Microsoft Graph in a Node.js & Express web app: https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-nodejs-webapp-msal
Example: Acquiring tokens with ADAL Node vs. MSAL Node:https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-node-migration#example-acquiring-tokens-with-adal-node-vs-msal-node
NodeJS Express + MSAL 應(yīng)用實現(xiàn)AAD集成登錄并部署在App Service Linux環(huán)境中的實現(xiàn)步驟:https://www.cnblogs.com/lulight/p/16353145.html
NodeJS Express + MSAL 應(yīng)用實現(xiàn)AAD登錄并獲取AccessToken -- cca.acquireTokenByCode(tokenRequest):https://www.cnblogs.com/lulight/p/16357246.html
當(dāng)在復(fù)雜的環(huán)境中面臨問題外潜,格物之道需:濁而靜之徐清原环,安以動之徐生。 云中处窥,恰是如此!
分類: 【Azure 應(yīng)用服務(wù)】, 【Azure 環(huán)境】, 【Azure Developer】
標簽: App Service, Azure Developer, Azure 環(huán)境, NodeJS + Express, API Authorization Token, passport.authenticate