教學課程:在您的 Node.js Web 應用程式中新增登入和登出
本教學課程是系列中的最後一個部分,示範如何使用 Microsoft Entra 系統管理中心來建置 Node.js Web 應用程式並準備進行驗證。 在此系列的第 2 部分中,您已建立 Node.js Web 應用程式並組織所有必要的檔案。 在本教學課程中,您將新增 Node.js Web 應用程式的登入、註冊和登出。 若要簡化將驗證新增至 Node.js Web 應用程式,您可使用適用於 Node 的 Microsoft 驗證程式庫 (MSAL)。 登入流程會使用 OpenID Connect (OIDC) 驗證通訊協定,安全地登入使用者。
在本教學課程中,您將會:
- 增登入和登出邏輯
- 檢視 ID 權杖宣告
- 執行應用程式及測試登入和登出體驗。
必要條件
- 您已完成教學課程:準備 Node.js Web 應用程式進行驗證中的步驟。
建立 MSAL 設定物件
在您的程式碼編輯器中,開啟 authConfig.js 檔案,然後新增下列程式碼:
require('dotenv').config();
const TENANT_SUBDOMAIN = process.env.TENANT_SUBDOMAIN || 'Enter_the_Tenant_Subdomain_Here';
const REDIRECT_URI = process.env.REDIRECT_URI || 'http://localhost:3000/auth/redirect';
const POST_LOGOUT_REDIRECT_URI = process.env.POST_LOGOUT_REDIRECT_URI || 'http://localhost:3000';
/**
* Configuration object to be passed to MSAL instance on creation.
* For a full list of MSAL Node configuration parameters, visit:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md
*/
const msalConfig = {
auth: {
clientId: process.env.CLIENT_ID || 'Enter_the_Application_Id_Here', // 'Application (client) ID' of app registration in Azure portal - this value is a GUID
authority: process.env.AUTHORITY || `https://${TENANT_SUBDOMAIN}.ciamlogin.com/`, // replace "Enter_the_Tenant_Subdomain_Here" with your tenant name
clientSecret: process.env.CLIENT_SECRET || 'Enter_the_Client_Secret_Here', // Client secret generated from the app registration in Azure portal
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: 'Info',
},
},
};
module.exports = {
msalConfig,
REDIRECT_URI,
POST_LOGOUT_REDIRECT_URI,
TENANT_SUBDOMAIN
};
msalConfig
物件包含一組設定選項,可用來自訂驗證流程的行為。
在 authConfig.js 檔案中,取代:
Enter_the_Application_Id_Here
成為您稍早所註冊應用程式的應用程式 (用戶端) 識別碼。Enter_the_Tenant_Subdomain_Here
並將它取代為 Directory (租用戶) 子網域。 例如,若租用戶主要網域是contoso.onmicrosoft.com
,請使用contoso
。 如果您沒有租用戶名稱,請了解如何閱讀租用戶詳細資料。Enter_the_Client_Secret_Here
成為您稍早複製的應用程式秘密值。
如果您使用 .env 檔案來儲存組態資訊:
在程式碼編輯器中,開啟 .env 檔案,然後新增下列程式碼。
CLIENT_ID=Enter_the_Application_Id_Here TENANT_SUBDOMAIN=Enter_the_Tenant_Subdomain_Here CLIENT_SECRET=Enter_the_Client_Secret_Here REDIRECT_URI=http://localhost:3000/auth/redirect POST_LOGOUT_REDIRECT_URI=http://localhost:3000
如先前所述,取代
Enter_the_Application_Id_Here
、Enter_the_Tenant_Subdomain_Here
和Enter_the_Client_Secret_Here
預留位置。
您可以在 authConfig.js 檔案中匯出 msalConfig
、REDIRECT_URI
、TENANT_SUBDOMAIN
和 POST_LOGOUT_REDIRECT_URI
變數,以在您需要檔案時存取這些變數。
使用自訂 URL 網域 (選用)
使用自訂網域對驗證 URL 進行完整品牌化。 就使用者而言,使用者在驗證過程中一直停留在您的網域中,而不會重新導向至 ciamlogin.com 網域名稱。
使用下列步驟來使用自訂網域:
使用針對外部租用戶中的應用程式啟用自訂 URL 網域中的步驟,為外部租用戶啟用自訂 URL 網域。
在您的 authConfig.js 檔案中,找出
auth
物件,然後:- 將
authority
屬性的值更新為 https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here。 以您的自訂 URL 網域取代Enter_the_Custom_Domain_Here
,並以您的租用戶識別碼取代Enter_the_Tenant_ID_Here
。 如果您沒有租用戶識別碼,請了解如何讀取租用戶詳細資料。 - 新增具有值 [Enter_the_Custom_Domain_Here] 的
knownAuthorities
屬性。
- 將
對 authConfig.js 檔案進行變更之後,如果您的自訂 URL 網域為 login.contoso.com,且您的租用戶識別碼為 aaaabbbb-0000-cccc-1111-dddd2222eeee,則您的檔案看起來應該類似以下程式碼片段:
//...
const msalConfig = {
auth: {
authority: process.env.AUTHORITY || 'https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee',
knownAuthorities: ["login.contoso.com"],
//Other properties
},
//...
};
新增 Express 路由
Express 路由提供端點,可讓我們執行登入、登出和檢視 ID 權杖宣告等作業。
套用進入點
在您的程式碼編輯器中,開啟 routes/index.js 檔案,然後新增下列程式碼:
const express = require('express');
const router = express.Router();
router.get('/', function (req, res, next) {
res.render('index', {
title: 'MSAL Node & Express Web App',
isAuthenticated: req.session.isAuthenticated,
username: req.session.account?.username !== '' ? req.session.account?.username : req.session.account?.name,
});
});
module.exports = router;
/
路由是應用程式的進入點。 它會轉譯您稍早在建置應用程式 UI 元件中建立的 views/index.hbs 檢視。 isAuthenticated
是一個布林值變數,可決定您在檢視中看到的內容。
登入和登出
在程式碼編輯器中,開啟 routes/auth.js 檔案,然後將程式碼從 auth.js 新增至其中。
在程式碼編輯器中,開啟 controller/authController.js 檔案,然後將程式碼從 authController.js 新增至其中。
在程式碼編輯器中,開啟 auth/AuthProvider.js 檔案,然後將程式碼從 AuthProvider.js 新增至其中。
/signin
、/signout
和/redirect
路由定義於 routes/auth.js 檔案中,但您會在 auth/AuthProvider.js 類別中實作其邏輯。
login
方法會處理/signin
路由:它會觸授權碼流程的第一段來起始登入流程。
它會使用您稍早建立的 MSAL 組態物件
msalConfig
,初始化機密用戶端應用程式執行個體。const msalInstance = this.getMsalInstance(this.config.msalConfig);
getMsalInstance
方法已定義為:getMsalInstance(msalConfig) { return new msal.ConfidentialClientApplication(msalConfig); }
授權碼流程的第一段會產生授權碼要求 URL,然後重新導向至該 URL 以取得授權碼。 第一段是在
redirectToAuthCodeUrl
方法中實作。 請注意我們如何使用 MSALs getAuthCodeUrl 方法來產生授權碼 URL://... const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest); //...
然後,我們會重新導向至授權碼 URL 本身。
//... res.redirect(authCodeUrlResponse); //...
handleRedirect
方法會處理/redirect
路由:您稍早註冊 Web 應用程式時,在 Microsoft Entra 系統管理中心將此 URL 設定為 Web 應用程式的重新導向 URI。
此端點會實作授權碼流程使用的第二段。 它會使用 MSAL 的 acquireTokenByCode 方法,使用授權碼來要求 ID 權杖。
//... const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body); //...
收到回應之後,您可以建立 Express 工作階段並將您想要的任何資訊儲存在其中。 您需要包含
isAuthenticated
並將它設定為true
://... req.session.idToken = tokenResponse.idToken; req.session.account = tokenResponse.account; req.session.isAuthenticated = true; //...
logout
方法會處理/signout
路由:async logout(req, res, next) { /** * Construct a logout URI and redirect the user to end the * session with Azure AD. For more information, visit: * https://docs.microsoft.com/azure/active-directory/develop/v2-protocols-oidc#send-a-sign-out-request */ const logoutUri = `${this.config.msalConfig.auth.authority}${TENANT_SUBDOMAIN}.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=${this.config.postLogoutRedirectUri}`; req.session.destroy(() => { res.redirect(logoutUri); }); }
它會起始登出要求。
當您想要將使用者登出應用程式時,這不足以結束使用者的工作階段。 您必須將使用者重新導向至 logoutUri。 不然,使用者也許能夠向您的應用程式進行重新驗證,而不需要重新輸入其認證。 如果您的租用戶名稱是 contoso,則 logoutUri 看起來類似
https://contoso.ciamlogin.com/contoso.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000
。
檢視 ID 權杖宣告
在您的程式碼編輯器中,開啟 routes/users.js 檔案,然後新增下列程式碼:
const express = require('express');
const router = express.Router();
// custom middleware to check auth state
function isAuthenticated(req, res, next) {
if (!req.session.isAuthenticated) {
return res.redirect('/auth/signin'); // redirect to sign-in route
}
next();
};
router.get('/id',
isAuthenticated, // check if user is authenticated
async function (req, res, next) {
res.render('id', { idTokenClaims: req.session.account.idTokenClaims });
}
);
module.exports = router;
如果使用者經過驗證,/id
路由會使用 views/id.hbs 檢視來顯示 ID 權杖宣告。 您稍早在建置應用程式 UI 元件中新增了此檢視。
若要擷取特定 ID 權杖宣告,例如指定的名稱:
const givenName = req.session.account.idTokenClaims.given_name
完成您的 Web 應用程式
在程式碼編輯器中,開啟 app.js 檔案,然後將程式碼從 app.js 新增至其中。
在程式碼編輯器中,開啟 server.js 檔案,然後將程式碼從 server.js 新增至其中。
在程式碼編輯器中,開啟 package.json 檔案,然後將
scripts
屬性更新為:"scripts": { "start": "node server.js" }
執行並測試 Web 應用程式
在您的終端機中,確定您位於包含 Web 應用程式的專案資料夾中,例如
ciam-sign-in-node-express-web-app
。在終端內,執行下列 命令:
npm start
開啟瀏覽器,然後移至
http://localhost:3000
。 您應該會看到類似下列螢幕擷取畫面的頁面:頁面完成載入之後,請選取 [登入] 連結。 系統會提示您登入。
在登入頁面上,輸入您的 [電子郵件地址]、選取 [下一步]、輸入您的 [密碼],然後選取 [登入]。 如果您沒有帳戶,請選取 [沒有帳戶?建立一個] 連結,以啟動註冊流程。
如果您選擇註冊選項,在填寫電子郵件、一次性密碼、新密碼和更多帳戶詳細資料之後,您便能完成整個註冊流程。 您會看到類似下列螢幕擷取畫面的頁面。 如果您選擇登入選項,則會看到類似的頁面。
選取 [登出] 將使用者登出 Web 應用程式,或選取 [檢視 ID 權杖宣告] 以檢視所有 ID 權杖宣告。