在前两篇博文中,对NodeJS Express应用 使用MSAL + AAD实现用户登录并获取用户信息,获取Authorization信息 ( ID Token, Access Token).
### 【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
下载后的文件结构为:
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
在index.js代码中,实现了两个接口 /hello 和 /public。 /hello 接口添加了passport.authenticate认证,访问需要携带Authorization (JWT Token),而/public则无需认证。
//
// 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'\]});
}
);
//
//
验证效果:
在前端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目前生成的Token为OAuth v1.0, 而在API应用中 identityMetadata 使用的是v2.0的openid-configration。所以需要在ADD中修改当前注册应用的清单文件(Mainfest)中
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 应用实现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
手机扫一扫
移动阅读更方便
你可能感兴趣的文章