单页应用程序:登录和注销

了解如何将登录添加到单页应用程序的代码中。

在应用程序中获取用于访问 API 的令牌之前,需要经身份验证的用户上下文。 可以在 MSAL.js 中以两种方式将用户登录到应用程序:

也可选择传递 API 的作用域,该作用域需在用户登录时获得用户许可。

如果应用程序已经可以访问经身份验证的用户上下文或 ID 令牌,则可跳过登录步骤,直接获取令牌。 有关详细信息,请参阅具有用户提示的 SSO

在弹出窗口或重定向登录体验之间进行选择

在弹出窗口和重定向体验之间进行的选择取决于应用程序流:

  • 如果不希望用户在身份验证期间离开主应用程序页,建议使用弹出窗口方法。 由于身份验证重定向发生在弹出窗口中,系统会保留主应用程序的状态。

  • 如果用户的浏览器约束或策略禁用了弹出窗口,则可使用重定向方法。 请对 Internet Explorer 浏览器使用重定向方法,因为 Internet Explorer 上具有弹出窗口的已知问题

通过弹出窗口登录

const config = {
  auth: {
    clientId: "your_app_id",
    redirectUri: "your_app_redirect_uri", //defaults to application start page
    postLogoutRedirectUri: "your_app_logout_redirect_uri",
  },
};

const loginRequest = {
  scopes: ["User.ReadWrite"],
};

let accountId = "";

const myMsal = new PublicClientApplication(config);

myMsal
  .loginPopup(loginRequest)
  .then(function (loginResponse) {
    accountId = loginResponse.account.homeAccountId;
    // Display signed-in user content, call API, etc.
  })
  .catch(function (error) {
    //login failure
    console.log(error);
  });

使用重定向登录

const config = {
  auth: {
    clientId: "your_app_id",
    redirectUri: "your_app_redirect_uri", //defaults to application start page
    postLogoutRedirectUri: "your_app_logout_redirect_uri",
  },
};

const loginRequest = {
  scopes: ["User.ReadWrite"],
};

let accountId = "";

const myMsal = new PublicClientApplication(config);

function handleResponse(response) {
  if (response !== null) {
    accountId = response.account.homeAccountId;
    // Display signed-in user content, call API, etc.
  } else {
    // In case multiple accounts exist, you can select
    const currentAccounts = myMsal.getAllAccounts();

    if (currentAccounts.length === 0) {
      // no accounts signed-in, attempt to sign a user in
      myMsal.loginRedirect(loginRequest);
    } else if (currentAccounts.length > 1) {
      // Add choose account code here
    } else if (currentAccounts.length === 1) {
      accountId = currentAccounts[0].homeAccountId;
    }
  }
}

myMsal.handleRedirectPromise().then(handleResponse);

浏览器上的注销行为

用户登录并想要注销的应用越多,鉴于在浏览器中实现此类功能的方式有限,出现问题的可能性就越大。 Microsoft 的 Internet 隐私最佳做法建议,在用户可能想要注销应用的共享设备上,用户应使用浏览器的隐私/incognito 模式,并在离开设备之前关闭所有浏览器窗口。

在未共享的设备上,用户应利用操作系统锁屏,以便他们可以在设备上锁定或注销其整个操作系统会话。 Microsoft 使用其注销页面提醒用户这些最佳做法,以帮助提高用户隐私和安全性。

对于不选择采用安全方法的用户,应用可尝试为以下两种情况做好准备:

  1. 用户已直接从应用启动注销。
  2. 从与新应用共享登录状态但只管理自己的会话令牌/Cookie 的另一个应用启动注销。

对于第一种情况,以下部分介绍了多个选项,说明如何使用弹出窗口或重定向从本地应用注销用户。

对于从另一个应用启动注销的第二种情况,Microsoft 使用 OpenID Connect 的 Front Channel 注销进行联合注销。此实现存在一些限制,即第三方内容将被阻止,例如浏览器默认阻止第三方 Cookie 的情况。

如果阻止了前置通道通信,以下弹出窗口和重定向方法将结束终结点和本地应用的会话,但可能不会立即清除其他联合应用程序的会话。 对于保证的联合注销,无论浏览器行为如何,我们都建议用户采用最佳做法,使用隐私浏览或锁屏。

使用弹出窗口进行注销

此模式受支持,但与弹出窗口登录具有相同的限制,即浏览器约束或策略可以禁用弹出窗口。 MSAL.js v2 及更高版本提供了一种 logoutPopup 方法,该方法可清除浏览器存储中的缓存,并打开一个指向 Microsoft Entra 注销页面的弹出窗口。 注销后,Microsoft Entra ID会将弹出窗口重定向回应用程序,而 MSAL.js 将关闭弹出窗口。

可以通过设置 postLogoutRedirectUri 来配置此 URI(在注销后 Microsoft Entra ID 应重定向到此 URI)。 此 URI 应在应用程序注册中注册为重定向 URI。

还可配置 logoutPopup,在注销完成后将 mainWindowRedirectUri 作为请求的一部分进行传递,以将主窗口重定向到其他页面,例如主页或登录页面。

const config = {
  auth: {
    clientId: "your_app_id",
    redirectUri: "your_app_redirect_uri", // defaults to application start page
    postLogoutRedirectUri: "your_app_logout_redirect_uri",
  },
};

const myMsal = new PublicClientApplication(config);

// you can select which account application should sign out
const logoutRequest = {
  account: myMsal.getAccountByHomeId(homeAccountId),
  mainWindowRedirectUri: "your_app_main_window_redirect_uri",
};

await myMsal.logoutPopup(logoutRequest);

使用重定向进行注销

MSAL.js 在 v1 中提供了 logout 方法,在 v2 中引入了 logoutRedirect 方法,该方法可清除浏览器存储中的缓存,并将窗口重定向到 Microsoft Entra 注销页面。 注销后,Microsoft Entra ID 会重定向回默认情况下调用注销的页面。

由于用户不会看到 Microsoft 关于使用隐私浏览器和锁屏的 Internet 隐私最佳做法的提醒,SPA 应用可能还需要描述最佳做法并提醒用户关闭所有浏览器窗口。

可以通过设置 postLogoutRedirectUri 来配置此 URI(在注销后应该重定向到此 URI)。 此 URI 应在应用程序注册中注册为重定向 URI。

const config = {
  auth: {
    clientId: "your_app_id",
    redirectUri: "your_app_redirect_uri", //defaults to application start page
    postLogoutRedirectUri: "your_app_logout_redirect_uri",
  },
};

const myMsal = new PublicClientApplication(config);

// you can select which account application should sign out
const logoutRequest = {
  account: myMsal.getAccountByHomeId(homeAccountId),
};

myMsal.logoutRedirect(logoutRequest);

后续步骤

转到此方案中的下一篇文章:获取应用的令牌