问题描述

在前两篇博文中,对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 B2C : https://docs.microsoft.com/en-us/azure/active-directory-b2c/enable-authentication-in-node-web-app-with-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,所以很多参数配置有一点差别。 BearerStrategy的详细参数说明如下:

  • identityMetadata (Required)

    The metadata endpoint provided by the Microsoft Identity Portal that provides the keys and other important information at runtime. Examples:

    • v1 tenant-specific endpoint
      https://login.microsoftonline.com/your_tenant_name.onmicrosoft.com/.well-known/openid-configuration
    https://login.microsoftonline.com/your_tenant_guid/.well-known/openid-configuration
    • v1 common endpoint
      https://login.microsoftonline.com/common/.well-known/openid-configuration
    • v2 tenant-specific endpoint
      https://login.microsoftonline.com/your_tenant_name.onmicrosoft.com/v2.0/.well-known/openid-configuration
    https://login.microsoftonline.com/your_tenant_guid/v2.0/.well-known/openid-configuration
    • v2 common endpoint
      https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration

    For B2C, you can only use v2 tenant-specific endpoint.

  • clientID (Required)

    The client ID of your application in AAD (Azure Active Directory)

  • passReqToCallback (Conditional)

    Required to set to true if using req as the first paramter in the verify function, default value is false. See section 4.2.1.3 for more details.

  • isB2C (Conditional)

    Required to set to true if you are using B2C tenant.

  • policyName (Conditional)

    Required if you are using B2C tenant. It is a string starting with 'B2C_1_' (case insensitive).

  • validateIssuer (Conditional)

    Required to set to false if you don't want to validate issuer, default value is true. We validate the iss claim in id_token against user provided issuer values and the issuer value we get from tenant-specific endpoint. If you use common endpoint for identityMetadata and you want to validate issuer, then you must provide issuer, or provide tenantIdOrName in passport.authenticate.

  • issuer (Conditional)

    This can be a string or an array of strings. See validateIssuer for the situation that requires issuer.

  • allowMultiAudiencesInToken (Conditional)

    Required if you allow access_token whose aud claim contains multiple values.

  • scope (Optional)

    This value is an array of scopes you accept. If this value is provided, we will check if the token contains one of these accepted scopes. If this value is not provided, we won't check token scopes.

  • audience (Optional)

    Must be a string or an array of strings. We invalidate the aud claim in access_token against audience. The default value for audience is clientID.

  • loggingLevel (Optional)

    Logging level. 'info', 'warn' or 'error'.

  • loggingNoPII (Optional)

    If this is set to true, no personal information such as tokens and claims will be logged. The default value is true.

  • clockSkew (Optional)

    This value is the clock skew (in seconds) allowed in token validation. It must be a positive integer. The default value is 300 seconds.

  • proxy (optional)

This value is the proxy settings object: { port: 'proxyport', host: 'proxyhost', protocol: 'http' }

文档地址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 apphttps://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

【Azure 应用服务】NodeJS Express + MSAL 实现API应用Token认证(AAD OAuth2 idToken)的认证实验 -- passport.authenticate('oauth-bearer', {session: false})的更多相关文章

  1. 【Azure 应用服务】NodeJS Express + MSAL 应用实现AAD集成登录并部署在App Service Linux环境中的实现步骤

    问题描述 实现部署NodeJS Express应用在App Service Linux环境中,并且使用Microsoft Authentication  Library(MSAL)来实现登录Azure ...

  2. 【Azure 应用服务】NodeJS Express + MSAL 应用实现AAD登录并获取AccessToken -- cca.acquireTokenByCode(tokenRequest)

    问题描述 在上一篇博文 "[Azure 应用服务]NodeJS Express + MSAL 应用实现AAD集成登录并部署在App Service Linux环境中的实现步骤"中, ...

  3. nodejs+express+mongodb写api接口的简单尝试

    1:启动mongodb服务 我的mongoDB的安装目录:E:\mongoDB\bin,版本:3.4.9 打开cmd  -> e:(进入e盘) -> cd mongoDB/bin(进入mo ...

  4. Azure 应用服务中的 API 应用、ASP.NET 和 Swagger 入门

    学习内容: 如何通过 Visual Studio 2015 中的内置工具在 Azure 应用服务中创建和部署 API 应用. 如何使用 Swashbuckle NuGet 包动态生成 Swagger ...

  5. NodeJs接口token认证express框架passport实现方式Bearer认证

    1.生成一个简单的express项目(命令:express passport-test),项目结构如下: 2.添加项目依赖: npm install passport --save npm insta ...

  6. Nodejs Express 4.X 中文API 1--- Application篇

    相关阅读: Express 4.X API 翻译[一] --  Application篇 Express4.XApi 翻译[二] --  Request篇 Express4.XApi 翻译[三] -- ...

  7. Nodejs Express 4.X 中文API 4--- Router篇

    相关阅读: Express 4.X API 翻译[一] --  Application篇 Express4.XApi 翻译[二] --  Request篇 Express4.XApi 翻译[三] -- ...

  8. Nodejs Express 4.X 中文API 3--- Response篇

    相关阅读: Express 4.X API 翻译[一] --  Application篇 Express4.XApi 翻译[二] --  Request篇 Express4.XApi 翻译[三] -- ...

  9. Nodejs Express 4.X 中文API 2--- Request篇

    相关阅读: Express 4.X API 翻译[一] --  Application篇 Express4.XApi 翻译[二] --  Request篇 Express4.XApi 翻译[三] -- ...

随机推荐

  1. C语言---魔方阵

    魔方阵的定义:在n*n的方阵中,每一行的和=每一列的和=对角线的和.(本文中涉及的n为大于3的奇数). 例如3*3的魔方阵为: 5*5的魔方阵为: 如何写魔方阵呢? 1.数字1位于第一行的正中间2.下 ...

  2. Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found 解决办法

    问题 每次vs重启都提示安装证书,即使执行dotnet dev-certs https --clean,dotnet dev-certs https -t然后重启vs也不行. 环境 win10, vs ...

  3. HTML5有哪些更新(部分)

    1. 语义化标签 header:定义文档的页眉(头部): nav:定义导航链接的部分: footer:定义文档或节的页脚(底部): article:定义文章内容: section:定义文档中的节(se ...

  4. 变量 数据类型 条件if语句

    python是解释型  弱类型编程语言;  "优雅", "明确", "简单";  开发效率非常高;  可移植性;  可扩展性; 可嵌入型. ...

  5. redis的基础命令操作

    文章目录 前言 一.字符串类型 二.哈希类型 三.列表类型 四.集合类型 五.有序集合类型 六.通过命令 前言 redis的数据结构 redis存储的是key,value格式的数据,其中的key是字符 ...

  6. 时间篇之centos7修复ntpq: read: Connection refused

    关于ntp同步时间, 由于是解决问题,所以理论性内容不多. 关于UTC NTP要提供准确的时间,就必须有准确的时间来源,那可以用格林尼治时间吗?答案是否定的. 因为格林尼治时间是以地球自转为基础的时间 ...

  7. nfs客户端的一次处理

    为什么要说这个呢,由于节点环境不一致,导致在重建pod时,我们暂且叫该pod为 cxpod,cxpod所在宿主机出现了问题现象如下:一.cxpod始终处于创建中 ContainerCreating [ ...

  8. Unity中的2D层级显示问题

    ##1.层级显示 ###使用素材为免费或自制 本文章只用于学习和记录 在Unity2D游戏中可能出现以下情况 贴图的前后关系不正确 可以通过控制图片的层级来解决 本示例中杰西卡和树木都是搭载了图片的空 ...

  9. .NET 7 Preview 3添加了这些增强功能

    .NET 7 Preview 3 已发布, .NET 7 的第三个预览版包括对可观察性.启动时间.代码生成.GC Region.Native AOT 编译等方面的增强. 有兴趣的用户可以下载适用于 W ...

  10. pwn 之 沙箱机制

    0x00: 简介 沙箱机制,英文sandbox,是计算机领域的虚拟技术,常见于安全方向.一般说来,我们会将不受信任的软件放在沙箱中运行,一旦该软件有恶意行为,则禁止该程序的进一步运行,不会对真实系统造 ...