单一登录(SSO)通过减少用户要求提供凭据的次数,提供更无缝的体验。 用户输入凭据一次,并且同一设备上的其他应用程序可以重复使用已建立的会话,而无需进一步提示。
Microsoft Entra ID 通过在用户首次进行身份验证时设置会话 Cookie 来启用 SSO。 MSAL.js 还会按应用程序域在浏览器存储中缓存用户的 ID 令牌和访问令牌。 Microsoft Entra 会话 Cookie 和 Microsoft 身份验证库 (MSAL) 缓存这两种机制相互独立,但共同提供 SSO 行为。
同一应用的浏览器选项卡之间的 SSO
当用户在多个选项卡中打开一个应用程序并登录其中一个选项卡时,可以在其他选项卡上登录到打开的同一应用,而无需提示。 为此,需要在 MSAL.js 配置对象中设置 cacheLocation , localStorage 如以下示例所示:
const config = {
auth: {
clientId: "1111-2222-3333-4444-55555555",
},
cache: {
cacheLocation: "localStorage",
},
};
const msalInstance = new msal.PublicClientApplication(config);
在这种情况下,不同浏览器选项卡中的应用程序实例使用相同的 MSAL 缓存,从而在它们之间共享身份验证状态。 当用户从其他浏览器选项卡或窗口登录时,还可以使用 MSAL 事件来更新应用程序实例。 有关详细信息,请参阅: 跨选项卡和窗口同步登录状态
不同应用之间的 SSO
当用户进行身份验证时,浏览器会在 Microsoft Entra 域上设置一个会话 Cookie。 MSAL.js 依赖于此会话 Cookie 来为不同应用程序之间的用户提供 SSO。 具体而言,MSAL.js 提供 ssoSilent 登录用户的方法,无需交互即可获取令牌。 但是,如果用户在某个 Microsoft Entra ID 会话中拥有多个用户帐户,系统随后会提示他们选择一个帐户进行登录。 因此,有两种使用 ssoSilent 方法实现 SSO 的方式。
采用用户提示
为了提高性能并确保授权服务器查找正确的帐户会话,可以在方法的请求对象 ssoSilent 中传递以下选项之一以无提示方式获取令牌。
-
login_hint,可从account对象的 username 属性或 ID 令牌中的upn声明中检索。 如果你的应用使用 B2C 对用户进行身份验证,请参阅: 配置 B2C 用户流以在 ID 令牌中发出用户名 - 会话 ID,
sid,可从account对象的idTokenClaims中检索到。 -
account,可通过使用账户方法之一来获取
我们建议使用提供给 ssoSilent 的login_hint可选 ID 令牌声明作为 loginHint,因为它是无提示和交互式请求的最可靠的帐户提示。
使用登录提示
login_hint 可选声明向 Microsoft Entra ID 提供有关尝试登录的用户帐户的提示。 若要绕过通常在交互式身份验证请求期间显示的帐户选择提示,请提供 loginHint 如下所示:
const silentRequest = {
scopes: ["User.Read", "Mail.Read"],
loginHint: "user@contoso.com"
};
try {
const loginResponse = await msalInstance.ssoSilent(silentRequest);
} catch (err) {
if (err instanceof InteractionRequiredAuthError) {
const loginResponse = await msalInstance.loginPopup(silentRequest).catch(error => {
// handle error
});
} else {
// handle error
}
}
在此示例中, loginHint 包含用户在交互式令牌请求期间用作提示的电子邮件或 UPN。 可以在应用程序之间传递提示以方便无提示 SSO,其中应用程序 A 可以登录用户,读取loginHint声明,然后将当前租户上下文发送到应用程序 B。Microsoft Entra ID将尝试预填充登录表单或绕过帐户选择提示,并直接执行指定用户的身份验证过程。
如果声明中 login_hint 的信息与任何现有用户不匹配,则会重定向这些用户,以经历标准登录体验,包括帐户选择。
使用会话 ID
若要使用会话 ID,请将 sid 作为可选声明添加到应用的 ID 令牌。 声明sid允许应用程序标识用户的Microsoft Entra会话,独立于其帐户名或用户名。 若要了解如何添加可选声明(如 sid),请参阅 为应用提供可选声明。 在使用 MSAL.js 中的 ssoSilent 发出的无提示身份验证请求中使用会话 ID (SID)。
const request = {
scopes: ["user.read"],
sid: sid,
};
try {
const loginResponse = await msalInstance.ssoSilent(request);
} catch (err) {
if (err instanceof InteractionRequiredAuthError) {
const loginResponse = await msalInstance.loginPopup(request).catch(error => {
// handle error
});
} else {
// handle error
}
}
使用帐户对象
如果知道用户帐户信息,还可以使用 getAccountByUsername() 或 getAccountByHomeId() 方法检索用户帐户:
const username = "test@contoso.com";
const myAccount = msalInstance.getAccountByUsername(username);
const request = {
scopes: ["User.Read"],
account: myAccount
};
try {
const loginResponse = await msalInstance.ssoSilent(request);
} catch (err) {
if (err instanceof InteractionRequiredAuthError) {
const loginResponse = await msalInstance.loginPopup(request).catch(error => {
// handle error
});
} else {
// handle error
}
}
没有用户提示
您可以尝试使用 ssoSilent 方法,而不传递任何 account、sid 或 login_hint 参数,如以下代码所示:
const request = {
scopes: ["User.Read"]
};
try {
const loginResponse = await msalInstance.ssoSilent(request);
} catch (err) {
if (err instanceof InteractionRequiredAuthError) {
const loginResponse = await msalInstance.loginPopup(request).catch(error => {
// handle error
});
} else {
// handle error
}
}
但是,如果应用程序在单个浏览器会话中有多个用户,或者用户具有该单个浏览器会话的多个帐户,则可能会出现无提示登录错误。 如果有多个帐户可用,可能会显示以下错误:
InteractionRequiredAuthError: interaction_required: AADSTS16000: Either multiple user identities are available for the current request or selected account is not supported for the scenario.
错误指示服务器无法确定要登录的帐户,并且需要上一个示例(account、 login_hint、 sid)中的某个参数或交互式登录来选择该帐户。
使用时的注意事项 ssoSilent
重定向 URI (回复 URL)
为了获得更好的性能并帮助避免问题,请将该页设置为 redirectUri 空白页或其他不使用 MSAL 的页面。
- 如果应用程序仅使用弹出式方法和静默方法,请在
PublicClientApplication配置对象上设置redirectUri。 - 如果应用程序还使用重定向方法,请根据请求设置
redirectUri。
第三方 Cookie
ssoSilent尝试打开隐藏的 iframe 并重复使用具有Microsoft Entra ID的现有会话。 这不适用于阻止第三方 Cookie(如 Safari)的浏览器,并会导致交互错误:
InteractionRequiredAuthError: login_required: AADSTS50058: A silent sign-in request was sent but no user is signed in. The cookies used to represent the user's session were not sent in the request to Azure AD
若要解决此错误,用户必须使用 loginPopup() 或 loginRedirect() 创建交互式身份验证请求。 在某些情况下,提示值 none 可以与交互式 MSAL.js 方法配合使用来实现 SSO。 有关更多内容,请参阅 包含 prompt=none 的交互式请求 。 如果已有用户的登录信息,则可以传递 loginHint 或 sid 可选参数以登录特定帐户。
通过 prompt=login 取消 SSO
如果在与授权服务器存在活动会话的情况下仍希望 Microsoft Entra ID 提示用户输入凭据,则可以通过 MSAL.js 在请求中使用登录提示参数。 有关详细信息 ,请参阅MSAL.js 提示行为 。
在 ADAL.js 和 MSAL.js 之间共享身份验证状态
MSAL.js 在 Microsoft Entra 身份验证场景中实现了与 ADAL.js 的功能对等。 若要使从 ADAL.js 迁移到 MSAL.js 在应用之间轻松共享身份验证状态,库会读取表示 ADAL.js 缓存中用户会话的 ID 令牌。 若要在从 ADAL.js 迁移时利用这一点,需要确保这些库使用 localStorage 来缓存令牌。 在初始化时,按如下所示,在 MSAL.js 和 ADAL.js 的配置中都将 cacheLocation 设置为 localStorage:
// In ADAL.js
window.config = {
clientId: "1111-2222-3333-4444-55555555",
cacheLocation: "localStorage",
};
var authContext = new AuthenticationContext(config);
// In latest MSAL.js version
const config = {
auth: {
clientId: "1111-2222-3333-4444-55555555",
},
cache: {
cacheLocation: "localStorage",
},
};
const msalInstance = new msal.PublicClientApplication(config);
后续步骤
有关 SSO 的详细信息,请参阅: