教程:在 Vanilla JavaScript SPA 中处理身份验证流
本教程是一系列教程的第 3 部分,演示如何生成 Vanilla JavaScript (JS) 单页应用程序 (SPA),并准备将其用于身份验证。 在本教程系列的第 2 部分,你创建了一个 Vanilla JS SPA,并已准备好通过外部租户对其进行身份验证。 在本教程中,你将了解如何通过添加 Microsoft 身份验证库 (MSAL) 组件来处理应用中的身份验证流。
在本教程中;
- 配置应用程序的设置
- 向 authRedirect.js 添加代码以处理身份验证流
- 向 authPopup.js 添加代码以处理身份验证流
先决条件
编辑身份验证配置文件
打开 public/authConfig.js 并添加以下代码片段:
import { LogLevel } from '@azure/msal-browser'; /** * Configuration object to be passed to MSAL instance on creation. * For a full list of MSAL.js configuration parameters, visit: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md */ export const msalConfig = { auth: { clientId: 'Enter_the_Application_Id_Here', // This is the ONLY mandatory field that you need to supply. authority: 'https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/', // Replace the placeholder with your tenant subdomain redirectUri: '/', // Points to window.location.origin. You must register this URI on Azure Portal/App Registration. postLogoutRedirectUri: '/', // Indicates the page to navigate after logout. navigateToLoginRequestUrl: false, // If "true", will navigate back to the original request location before processing the auth code response. }, cache: { cacheLocation: 'sessionStorage', // Configures cache location. "sessionStorage" is more secure, but "localStorage" gives you SSO between tabs. storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge }, system: { loggerOptions: { loggerCallback: (level, message, containsPii) => { if (containsPii) { return; } switch (level) { case LogLevel.Error: console.error(message); return; case LogLevel.Info: console.info(message); return; case LogLevel.Verbose: console.debug(message); return; case LogLevel.Warning: console.warn(message); return; default: return; } }, }, }, }; /** * Scopes you add here will be prompted for user consent during sign-in. * By default, MSAL.js will add OIDC scopes (openid, profile, email) to any login request. * For more information about OIDC scopes, visit: * https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes */ export const loginRequest = { scopes: [], };
将以下值替换为 Azure 门户中的值:
- 找到
Enter_the_Application_Id_Here
值并将其替换为你在 Microsoft Entra 管理中心注册的应用的应用程序 ID (clientId)。- 在“颁发机构”中,找到
Enter_the_Tenant_Subdomain_Here
并将其替换为租户的子域。 例如,如果租户主域为contoso.onmicrosoft.com
,请使用contoso
。 如果没有租户名称,请了解如何读取租户详细信息。
- 在“颁发机构”中,找到
- 找到
保存文件。
使用自定义 URL 域(可选)
使用自定义域可完全标记身份验证 URL。 从用户的角度来看,用户在身份验证过程中仍留在你的域中,而不是重定向到 ciamlogin.com 域名。
通过以下步骤使用自定义域:
使用为外部租户中的应用启用自定义 URL 域中的步骤为外部租户启用自定义 URL 域。
在 authConfig.js 文件中,找到
auth
对象,然后执行以下操作:- 将
authority
属性的值更新为 https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here。 将Enter_the_Custom_Domain_Here
替换为你的自定义 URL 域,并将Enter_the_Tenant_ID_Here
替换为你的租户 ID。 如果没有租户 ID,请了解如何读取租户详细信息。 - 添加值为 [Enter_the_Custom_Domain_Here] 的
knownAuthorities
属性。
- 将
对 authConfig.js 文件进行更改后,如果自定义 URL 域为 login.contoso.com 且租户 ID 为 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
},
//...
};
向重定向文件添加代码
需要重定向文件来处理来自登录页的响应。 该文件用于从 URL 片段中提取访问令牌,并用其调用受保护的 API。 它还用于处理在身份验证过程中发生的错误。
打开 public/authRedirect.js 并添加以下代码片段:
// Create the main myMSALObj instance // configuration parameters are located at authConfig.js const myMSALObj = new msal.PublicClientApplication(msalConfig); let username = ""; /** * A promise handler needs to be registered for handling the * response returned from redirect flow. For more information, visit: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/initialization.md#redirect-apis */ myMSALObj.handleRedirectPromise() .then(handleResponse) .catch((error) => { console.error(error); }); function selectAccount() { /** * See here for more info on account retrieval: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md */ const currentAccounts = myMSALObj.getAllAccounts(); if (!currentAccounts) { return; } else if (currentAccounts.length > 1) { // Add your account choosing logic here console.warn("Multiple accounts detected."); } else if (currentAccounts.length === 1) { username = currentAccounts[0].username welcomeUser(currentAccounts[0].username); updateTable(currentAccounts[0]); } } function handleResponse(response) { /** * To see the full list of response object properties, visit: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#response */ if (response !== null) { username = response.account.username welcomeUser(username); updateTable(response.account); } else { selectAccount(); } } function signIn() { /** * You can pass a custom request object below. This will override the initial configuration. For more information, visit: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request */ myMSALObj.loginRedirect(loginRequest); } function signOut() { /** * You can pass a custom request object below. This will override the initial configuration. For more information, visit: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request */ // Choose which account to logout from by passing a username. const logoutRequest = { account: myMSALObj.getAccountByUsername(username), postLogoutRedirectUri: '/signout', // remove this line if you would like navigate to index page after logout. }; myMSALObj.logoutRedirect(logoutRequest); }
保存文件。
向 authPopup.js 文件添加代码
当用户使用弹出窗口登录时,应用程序使用 authPopup.js 来处理身份验证流。 如果用户已登录,而应用程序需要获取另一资源的访问令牌时,则使用弹出窗口。
打开 public/authPopup.js 并添加以下代码片段:
// Create the main myMSALObj instance // configuration parameters are located at authConfig.js const myMSALObj = new msal.PublicClientApplication(msalConfig); let username = ""; function selectAccount () { /** * See here for more info on account retrieval: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-common/docs/Accounts.md */ const currentAccounts = myMSALObj.getAllAccounts(); if (!currentAccounts || currentAccounts.length < 1) { return; } else if (currentAccounts.length > 1) { // Add your account choosing logic here console.warn("Multiple accounts detected."); } else if (currentAccounts.length === 1) { username = currentAccounts[0].username welcomeUser(currentAccounts[0].username); updateTable(currentAccounts[0]); } } function handleResponse(response) { /** * To see the full list of response object properties, visit: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#response */ if (response !== null) { username = response.account.username welcomeUser(username); updateTable(response.account); } else { selectAccount(); } } function signIn() { /** * You can pass a custom request object below. This will override the initial configuration. For more information, visit: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request */ myMSALObj.loginPopup(loginRequest) .then(handleResponse) .catch(error => { console.error(error); }); } function signOut() { /** * You can pass a custom request object below. This will override the initial configuration. For more information, visit: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/request-response-object.md#request */ // Choose which account to logout from by passing a username. const logoutRequest = { account: myMSALObj.getAccountByUsername(username), mainWindowRedirectUri: '/signout' }; myMSALObj.logoutPopup(logoutRequest); } selectAccount();
保存文件。