【Azure 应用服务】NodeJS Express + MSAL 实现API应用Token认证(AAD OAuth2 idToken)的认证实验 -- passport.authenticate()

简介: 【Azure 应用服务】NodeJS Express + MSAL 实现API应用Token认证(AAD OAuth2 idToken)的认证实验 -- passport.authenticate()

问题描述

在前两篇博文中,对NodeJS Express应用 使用MSAL + AAD实现用户登录并获取用户信息,获取Authorization信息 ( ID Token, Access Token).

  1. 【Azure 应用服务】NodeJS Express + MSAL 应用实现AAD集成登录并部署在App Service Linux环境中的实现步骤
  2. 【Azure 应用服务】NodeJS Express + MSAL 应用实现AAD登录并获取AccessToken -- cca.acquireTokenByCode(tokenRequest)

而在当前这篇博文中,我们将会实现以下目的:

1)为NodeJS API应用配置Bearer Token验证组件 passport 和 passport-azure-ad

2)实现使用idToken验证并访问API

 

 

实现步骤

在完成Azure AD中的注册应用配置后,并且根据博文“ NodeJS Express + MSAL 应用实现AAD登录并获取AccessToken -- cca.acquireTokenByCode(tokenRequest): https://www.cnblogs.com/lulight/p/16357246.html” 完成用户登录的前端应用,

参考官方示例 “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

下载后的文件结构为:

第二步:修改config.json 文件和index.js中的 identityMetadata 值

options中即为 BearerStrategy的配置参数,因为当前不适用AAD B2C,而是直接使用AAD,所以isB2C就需要设置为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,所以很多参数配置有一点差别。

本次实验中使用的参数说明如下:

  • identityMetadata (必须字段):填写进行OAuth 2.0 认证的 Openid-configuration地址,如在中国区的地址为  'https://login.partner.microsoftonline.cn/<your tenant id>/v2.0/.well-known/openid-configuration'
  • clientID (必须字段): 为AAD中注册应用的Application ID
  • audience(可选):为一个字符串或者字符串数组,默认值为注册应用的Client ID
  • validateIssuer(可选):如果不需要验证Issuer这个参数,需要设置为false。默认值为true。当使用AAD的Openid-configuration信息,它会通过identitymetadata中获取 issuer信息
  • loggingLevel(可选):AAD Validation 的日志输出级别,有info,error,warn可供设置
  • passReqToCallback(可选):默认值为false,用户当请求的第一个参数中提供了验证函数时,需要设置为true

关于BearerStrategy参数更多详细说明请参考链接:https://github.com/AzureAD/passport-azure-ad#42-bearerstrategy

 

第三步:访问API接口(/hello 需要Authorization, /public 不需要Authorization)

在index.js代码中,实现了两个接口 /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注册应用的accessTokenAcceptedVersion

因为中国区AAD目前生成的Token为OAuth v1.0, 而在API应用中 identityMetadata  使用的是v2.0的openid-configration。所以需要在ADD中修改当前注册应用的清单文件(Mainfest)中

accessTokenAcceptedVersion 值为 2

  1. 登录Azure 门户,选择Azure AD。
  2. 点击 App registrations 并选择自己的应用,如本示例中的“ExpressWebApp”
  3. 进入应用Overview页面后,选择左侧导航中“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 应用实现AAD集成登录并部署在App Service Linux环境中的实现步骤https://www.cnblogs.com/lulight/p/16353145.html

NodeJS Express + MSAL 应用实现AAD登录并获取AccessToken -- cca.acquireTokenByCode(tokenRequest):https://www.cnblogs.com/lulight/p/16357246.html

 

相关文章
|
7月前
|
供应链 搜索推荐 数据挖掘
探秘京东 API 接口的神奇应用场景
京东API如同数字钥匙,助力商家实现商品、库存、订单等多平台高效同步,提升效率超80%。支持物流实时追踪,增强用户满意度;赋能精准营销与数据分析,决策准确率提升20%以上,全面优化电商运营。
191 1
|
8月前
|
人工智能 自然语言处理 机器人
使用 API 编程开发扣子应用
扣子(Coze)应用支持通过 API 编程,将 AI 聊天、内容生成、工作流自动化等功能集成至自有系统。主要 API 包括 Bot API(用于消息交互与会话管理)及插件与知识库 API(扩展功能与数据管理)。开发流程包括创建应用、获取密钥、调用 API 并处理响应,支持 Python 等语言。建议加强错误处理、密钥安全与会话管理,提升集成灵活性与应用扩展性。
2602 0
|
9月前
|
监控 供应链 搜索推荐
电商数据开发实践:深度剖析1688商品详情 API 的技术与应用
在电商数字化转型中,数据获取效率与准确性至关重要。本文介绍了一款高效商品详情API,具备全维度数据采集、价格库存管理、多媒体资源获取等功能,结合实际案例探讨其在电商开发中的应用价值与优势。
|
7月前
|
Ubuntu API C++
C++标准库、Windows API及Ubuntu API的综合应用
总之,C++标准库、Windows API和Ubuntu API的综合应用是一项挑战性较大的任务,需要开发者具备跨平台编程的深入知识和丰富经验。通过合理的架构设计和有效的工具选择,可以在不同的操作系统平台上高效地开发和部署应用程序。
297 11
|
8月前
|
人工智能 数据可视化 测试技术
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
1025 11
|
8月前
|
安全 API 数据安全/隐私保护
【Azure 环境】Microsoft Graph API实现对Entra ID中应用生成密码的时间天数
本文介绍如何通过 Azure 的 App Management Policy 限制用户在创建 AAD 应用程序的 Client Secret 时设置最长 90 天的有效期。通过 Microsoft Graph API 配置 defaultAppManagementPolicy,可有效控制密码凭据的生命周期,增强安全管理。
210 4
|
8月前
|
Java API 开发者
揭秘淘宝详情 API 接口:解锁电商数据应用新玩法
淘宝详情API是获取商品信息的“金钥匙”,可实时抓取标题、价格、库存等数据,广泛应用于电商分析、比价网站与智能选品。合法调用,助力精准营销与决策,推动电商高效发展。(238字)
326 0
|
JavaScript 前端开发 中间件
探索后端技术:Node.js与Express框架的完美融合
【10月更文挑战第7天】 在当今数字化时代,Web应用已成为日常生活不可或缺的一部分。本文将深入探讨后端技术的两大重要角色——Node.js和Express框架,分析它们如何通过其独特的特性和优势,为现代Web开发提供强大支持。我们将从Node.js的非阻塞I/O和事件驱动机制,到Express框架的简洁路由和中间件特性,全面解析它们的工作原理及应用场景。此外,本文还将分享一些实际开发中的小技巧,帮助你更有效地利用这些技术构建高效、可扩展的Web应用。无论你是刚入门的新手,还是经验丰富的开发者,相信这篇文章都能为你带来新的启发和思考。
|
前端开发 JavaScript NoSQL
使用 Node.js、Express 和 React 构建强大的 API
本文详细介绍如何使用 Node.js、Express 和 React 构建强大且动态的 API。从开发环境搭建到集成 React 前端,再到利用 APIPost 高效测试 API,适合各水平开发者。内容涵盖 Node.js 运行时、Express 框架与 React 库的基础知识及协同工作方式,还涉及数据库连接和前后端数据交互。通过实际代码示例,助你快速上手并优化应用性能。
|
JavaScript 中间件 关系型数据库
构建高效的后端服务:Node.js 与 Express 的实践指南
在后端开发领域,Node.js 与 Express 的组合因其轻量级和高效性而广受欢迎。本文将深入探讨如何利用这一组合构建高性能的后端服务。我们将从 Node.js 的事件驱动和非阻塞 I/O 模型出发,解释其如何优化网络请求处理。接着,通过 Express 框架的简洁 API,展示如何快速搭建 RESTful API。文章还将涉及中间件的使用,以及如何结合 MySQL 数据库进行数据操作。最后,我们将讨论性能优化技巧,包括异步编程模式和缓存策略,以确保服务的稳定性和扩展性。

热门文章

最新文章