MSAL 浏览器中的帐户

这是库的平台特定的帐户文档 @azure/msal-browser ,它提供以下 API 来访问缓存的帐户:

  • getAllAccounts():返回缓存中当前的所有帐户。 支持可选筛选器以返回一组特定的帐户。 应用程序必须选择帐户以无提示方式获取令牌。
  • getAccount():返回与传入的筛选器匹配的第一个缓存帐户。 从缓存中读取帐户的顺序是任意的,不能保证筛选列表中的第一个帐户对于任何两次 getAccount调用都将相同。 如下所述,增加筛选器属性的数量将提供更精确的匹配项。

帐户筛选器对象

AccountFilter 类型文档列出了可用于筛选帐户和组合的属性。

注释

通常不能保证单个帐户筛选器属性能够唯一标识缓存的帐户对象。 添加不一起重复的属性的组合,例如 homeAccountId + localAccountId,可以帮助优化搜索。

注释

realm 位于 tenantId 缓存中。

已弃用以下 getAccountBy API。 getAccount()请改用适当的筛选器对象:

  • getAccountByHomeId():请改用 getAccount({ homeAccountId })
  • getAccountByLocalId():请改用 getAccount({ localAccountId })
  • getAccountByUsername():请改用 getAccount({ username })

下面是涵盖这些 API 的用法示例:


let homeAccountId = null; // Initialize global accountId (can also be localAccountId or username) used for account lookup later, ideally stored in app state

// This callback is passed into `acquireTokenPopup` and `acquireTokenRedirect` to handle the interactive auth response
function handleResponse(resp) {
    if (resp !== null) {
        homeAccountId = resp.account.homeAccountId; // alternatively: resp.account.homeAccountId or resp.account.username
    } else {
        const currentAccounts = myMSALObj.getAllAccounts();
        if (currentAccounts.length < 1) { // No cached accounts
            return;
        } else if (currentAccounts.length > 1) { // Multiple account scenario
            // Add account selection code here
            homeAccountId = ...
        } else if (currentAccounts.length === 1) {
            homeAccountId = currentAccounts[0].homeAccountId; // Single account scenario
        }
    }
}

现在,帐户属性(例如: homeAccountIdlocalAccountId可用于 username 在以无提示方式获取令牌之前查找缓存的帐户:

// This method attempts silent token acquisition and falls back on acquireTokenPopup
async function getTokenPopup(request, homeAccountId) {
    // In this case, accounts are filtered by homeAccountId, but more attributes can be added to refine the search and increase the precision of the account filter
    const accountFilter = {
        homeAccountId: homeAccountId,
    };
    request.account = myMSALObj.getAccount(accountFilter);
    return await myMSALObj.acquireTokenSilent(request).catch(async (error) => {
        // Handle error
        return await myMSALObj.acquireTokenPopup(request);
    });
}

按登录提示进行筛选

因此 @azure/[email protected],所有登录提示值都可用于搜索和筛选帐户。 为了按登录提示进行筛选,MSAL 会将对象中的AccountFilter值与以下帐户属性(优先顺序)进行比较loginHint,以搜索匹配项:

  • login_hint ID 令牌声明
  • username account 属性
  • upn ID 令牌声明

注释

上述所有属性都可以作为属性传递到帐户筛选器 loginHint 中。 帐户筛选器也将接受该 username 属性, username并且将产生更高性能的搜索。

使用 login_hint 声明

const accountFilter = {
    loginHint: previouslyObtainedIdTokenClaims.login_hint;
};
request.account = myMSALObj.getAccount(accountFilter);
return await myMSALObj.acquireTokenSilent(request).catch(async (error) => {
    // Handle error
    return await myMSALObj.acquireTokenPopup(request);
});

使用“username”

注释

username 可以作为 AccountFilterusernameloginHint. 这是因为username声明是令牌服务作为登录提示接受的 3 个值之一(以及 upnlogin_hint ID 令牌声明)。 如果应用程序确定有问题的值为, username则将其设置为 AccountFilter.username 属性将产生更好的搜索性能。 如果应用程序使用登录提示,并且不保留该值来自某个usernamelogin_hintupn声明的上下文,则能够将值loginHint设置为username有用。

传递 usernameloginHint

const accountUsername = userProfile.username;
const accountFilter = {
    loginHint: accountUsername;
};
request.account = myMSALObj.getAccount(accountFilter);
return await myMSALObj.acquireTokenSilent(request).catch(async (error) => {
    // Handle error
    return await myMSALObj.acquireTokenPopup(request);
});

传递 usernameusername

const accountUsername = userProfile.username;
const accountFilter = {
    username: accountUsername;
};
request.account = myMSALObj.getAccount(accountFilter);
return await myMSALObj.acquireTokenSilent(request).catch(async (error) => {
    // Handle error
    return await myMSALObj.acquireTokenPopup(request);
});

使用 upn 声明

const accountFilter = {
    loginHint: previouslyObtainedIdTokenClaims.upn;
};
request.account = myMSALObj.getAccount(accountFilter);
return await myMSALObj.acquireTokenSilent(request).catch(async (error) => {
    // Handle error
    return await myMSALObj.acquireTokenPopup(request);
});

活动帐户 API

@azure/msal-browser 库还提供了 2 个方便的 API,可帮助你跟踪当前“活动”的帐户,并应用于令牌请求。

  • getActiveAccount():返回当前活动帐户
  • setActiveAccount():接收帐户对象并将其设置为活动帐户

但是,确定要用于获取令牌的帐户取决于应用,但确定要使用的帐户后,只需使用所选帐户对象调用 setActiveAccount() API。 如果acquireToken单个请求中未指定其他帐户,则ssoSilent任何调用login现在都将使用活动帐户。 若要清除当前处于活动状态的帐户,可以调用 setActiveAccount(null)

function login() {
    return myMsalObj.loginPopup().then((response) => {
        // After a successful login set the active account to be the user that just logged in
        myMsalObj.setActiveAccount(response.account);
    });
}

function getAccessToken() {
    // Providing an account in the token request is not required if there is an active account set
    return myMsalObj.acquireTokenSilent({ scopes: ["User.Read"] });
}

注意:从版本 2.16.0 起,活动帐户存储在实例上 PublicClientApplication 配置的缓存位置。 如果使用以前的版本,活动帐户将存储在内存中,因此必须在每次页面加载时重置。

嵌套应用身份验证

对于 NAA 应用程序, setActiveAccount() NO-OP getActiveAccount() API。 尽管用户可以设置和获取活动帐户,但它们会被主动忽略,因为 NAA 应用程序始终应有 一个 帐户,并且该帐户由主机应用程序提供 accountContext。 将来,当跨中心支持多个帐户时,此行为预计将发生更改。

备注

  • 当前的 msal-browser 默认 示例 具有一个工作单帐户方案。
  • 如果你有多个帐户方案,请修改 示例 (in handleResponse())以列出所有缓存帐户并选择特定的帐户。
  • 如果应用程序希望基于帐户username检索帐户,则需要在 API 中使用username筛选器之前保存username(从特定用户的 API 响应logingetAccount())。
  • getAllAccounts() 如果已发出多个交互式令牌请求,并且用户在两个或多个交互中选择了不同的帐户,将返回多个帐户。 可能需要传递或prompt: "login"传递给prompt: "select_account"交互式 acquireToken 或登录 API,以便Microsoft Entra ID在第一次交互后显示帐户选择屏幕。
  • 帐户 API 返回本地帐户状态,不一定反映服务器状态。 它们返回以前使用 MSAL.js 登录到此应用的帐户,并且服务器会话可能仍然处于活动状态或可能仍然处于活动状态。
  • 由于浏览器存储被域分列,托管在不同域上的两个应用不会共享帐户状态。
  • getAllAccounts() 未排序,不能保证跨多个调用的顺序相同
  • 每次成功调用 acquireToken 或登录 API 将只返回一个帐户