【Azure 應(yīng)用服務(wù)】NodeJS Express + MSAL 實現(xiàn)API應(yīng)用Token認證(AAD OAuth2 idToken)的認證實驗 -- passport.authenticate()

問題描述

在前兩篇博文中,對NodeJS Express應(yīng)用 使用MSAL + AAD實現(xiàn)用戶登錄并獲取用戶信息督赤,獲取Authorization信息 ( ID Token, Access Token).

  1. 【Azure 應(yīng)用服務(wù)】NodeJS Express + MSAL 應(yīng)用實現(xiàn)AAD集成登錄并部署在App Service Linux環(huán)境中的實現(xiàn)步驟
  2. 【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


image.png

實現(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 B2Chttps://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)為:


image.png

第二步:修改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>

驗證效果:


image.png

第四步:驗證 idToken 和 accessToken

在前端UI頁面通過登錄后獲取到Token信息, http://localhost:3000/auth

image.png

驗證展示動畫:

api token validation.gif

使用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


image.png
  1. 登錄Azure 門戶,選擇Azure AD橘霎。
  2. 點擊 App registrations 并選擇自己的應(yīng)用蔫浆,如本示例中的“ExpressWebApp”
  3. 進入應(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-Inhttps://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 Nodehttps://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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嘱吗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子滔驾,更是在濱河造成了極大的恐慌谒麦,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哆致,死亡現(xiàn)場離奇詭異绕德,居然都是意外死亡,警方通過查閱死者的電腦和手機摊阀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門耻蛇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來踪蹬,“玉大人,你說我怎么就攤上這事臣咖≡镜罚” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵亡哄,是天一觀的道長枝缔。 經(jīng)常有香客問我,道長蚊惯,這世上最難降的妖魔是什么愿卸? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮截型,結(jié)果婚禮上趴荸,老公的妹妹穿的比我還像新娘。我一直安慰自己宦焦,他們只是感情好发钝,可當(dāng)我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著波闹,像睡著了一般酝豪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上精堕,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天孵淘,我揣著相機與錄音,去河邊找鬼歹篓。 笑死瘫证,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的庄撮。 我是一名探鬼主播背捌,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼洞斯!你這毒婦竟也來了毡庆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤烙如,失蹤者是張志新(化名)和其女友劉穎么抗,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厅翔,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年搀突,在試婚紗的時候發(fā)現(xiàn)自己被綠了刀闷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖甸昏,靈堂內(nèi)的尸體忽然破棺而出顽分,到底是詐尸還是另有隱情,我是刑警寧澤施蜜,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布卒蘸,位于F島的核電站,受9級特大地震影響翻默,放射性物質(zhì)發(fā)生泄漏缸沃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一修械、第九天 我趴在偏房一處隱蔽的房頂上張望趾牧。 院中可真熱鬧,春花似錦肯污、人聲如沸翘单。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哄芜。三九已至,卻和暖如春柬唯,著一層夾襖步出監(jiān)牢的瞬間认臊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工权逗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留美尸,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓斟薇,卻偏偏與公主長得像师坎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子堪滨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容