将适用于 Android 的 MSAL 与 B2C 配合使用Use MSAL for Android with B2C

借助 Microsoft 身份验证库 (MSAL),应用程序开发人员可以使用 Azure Active Directory B2C (Azure AD B2C) 通过社交和本地标识对用户进行身份验证。Microsoft Authentication Library (MSAL) enables application developers to authenticate users with social and local identities by using Azure Active Directory B2C (Azure AD B2C). Azure AD B2C 是一个标识管理服务。Azure AD B2C is an identity management service. 使用该服务可以在客户使用你的应用程序时,自定义和控制他们的注册和登录方式以及管理其个人资料。Use it to customize and control how customers sign up, sign in, and manage their profiles when they use your applications.

配置已知的颁发机构和重定向 URIConfigure known authorities and redirect URI

在适用于 Android 的 MSAL 中,B2C 策略(用户旅程)配置为单独的颁发机构。In MSAL for Android, B2C policies (user journeys) are configured as individual authorities.

假设某个 B2C 应用程序有两个策略:Given a B2C application that has two policies:

  • 注册/登录Sign-up / Sign-in
    • 名为 B2C_1_SISOPolicyCalled B2C_1_SISOPolicy
  • 编辑个人资料Edit Profile
    • 名为 B2C_1_EditProfileCalled B2C_1_EditProfile

应用的配置文件将声明两个 authoritiesThe configuration file for the app would declare two authorities. 对每个策略各声明一个。One for each policy. 每个颁发机构的 type 属性为 B2CThe type property of each authority is B2C.

app/src/main/res/raw/msal_config.json

{
    "client_id": "<your_client_id_here>",
    "redirect_uri": "<your_redirect_uri_here>",
    "authorities": [{
            "type": "B2C",
            "authority_url": "https://contoso.b2clogin.cn/tfp/contoso.partner.onmschina.cn/B2C_1_SISOPolicy/",
            "default": true
        },
        {
            "type": "B2C",
            "authority_url": "https://contoso.b2clogin.cn/tfp/contoso.partner.onmschina.cn/B2C_1_EditProfile/"
        }
    ]
}

redirect_uri 必须在应用配置中注册,此外还必须在 AndroidManifest.xml 中注册,以便在运行授权代码授予流期间支持重定向。The redirect_uri must be registered in the app configuration, and also in AndroidManifest.xml to support redirection during the authorization code grant flow.

初始化 IPublicClientApplicationInitialize IPublicClientApplication

IPublicClientApplication 由某个工厂方法构造,使用它可以异步方式分析应用程序配置。IPublicClientApplication is constructed by a factory method to allow the application configuration to be parsed asynchronously.

PublicClientApplication.createMultipleAccountPublicClientApplication(
    context, // Your application Context
    R.raw.msal_config, // Id of app JSON config
    new IPublicClientApplication.ApplicationCreatedListener() {
        @Override
        public void onCreated(IMultipleAccountPublicClientApplication pca) {
            // Application has been initialized.
        }

        @Override
        public void onError(MsalException exception) {
            // Application could not be created.
            // Check Exception message for details.
        }
    }
);

以交互方式获取令牌Interactively acquire a token

若要使用 MSAL 以交互方式获取令牌,请生成一个 AcquireTokenParameters 实例并将其提供给 acquireToken 方法。To acquire a token interactively with MSAL, build an AcquireTokenParameters instance and supply it to the acquireToken method. 以下令牌请求使用 default 颁发机构。The token request below uses the default authority.

IMultipleAccountPublicClientApplication pca = ...; // Initialization not shown

AcquireTokenParameters parameters = new AcquireTokenParameters.Builder()
    .startAuthorizationFromActivity(activity)
    .withScopes(Arrays.asList("https://contoso.partner.onmschina.cn/contosob2c/read")) // Provide your registered scope here
    .withPrompt(Prompt.LOGIN)
    .callback(new AuthenticationCallback() {
        @Override
        public void onSuccess(IAuthenticationResult authenticationResult) {
            // Token request was successful, inspect the result
        }

        @Override
        public void onError(MsalException exception) {
            // Token request was unsuccessful, inspect the exception
        }

        @Override
        public void onCancel() {
            // The user cancelled the flow
        }
    }).build();

pca.acquireToken(parameters);

以静默方式续订令牌Silently renew a token

若要使用 MSAL 以静默方式获取令牌,请生成一个 AcquireTokenSilentParameters 实例并将其提供给 acquireTokenSilentAsync 方法。To acquire a token silently with MSAL, build an AcquireTokenSilentParameters instance and supply it to the acquireTokenSilentAsync method. acquireToken 方法不同,必须指定 authority 才能以静默方式获取令牌。Unlike the acquireToken method, the authority must be specified to acquire a token silently.

IMultilpeAccountPublicClientApplication pca = ...; // Initialization not shown
AcquireTokenSilentParameters parameters = new AcquireTokenSilentParameters.Builder()
    .withScopes(Arrays.asList("https://contoso.partner.onmschina.cn/contosob2c/read")) // Provide your registered scope here
    .forAccount(account)
    // Select a configured authority (policy), mandatory for silent auth requests
    .fromAuthority("https://contoso.b2clogin.cn/tfp/contoso.partner.onmschina.cn/B2C_1_SISOPolicy/")
    .callback(new SilentAuthenticationCallback() {
        @Override
        public void onSuccess(IAuthenticationResult authenticationResult) {
            // Token request was successful, inspect the result
        }

        @Override
        public void onError(MsalException exception) {
            // Token request was unsuccesful, inspect the exception
        }
    })
    .build();

pca.acquireTokenSilentAsync(parameters);

指定策略Specify a policy

由于 B2C 中的策略以单独的颁发机构表示,因此,可以通过在构造 acquireTokenacquireTokenSilent 参数时指定 fromAuthority 子句,来调用除默认策略以外的策略。Because policies in B2C are represented as separate authorities, invoking a policy other than the default is achieved by specifying a fromAuthority clause when constructing acquireToken or acquireTokenSilent parameters. 例如:For example:

AcquireTokenParameters parameters = new AcquireTokenParameters.Builder()
    .startAuthorizationFromActivity(activity)
    .withScopes(Arrays.asList("https://contoso.partner.onmschina.cn/contosob2c/read")) // Provide your registered scope here
    .withPrompt(Prompt.LOGIN)
    .callback(...) // provide callback here
    .fromAuthority("<url_of_policy_defined_in_configuration_json>")
    .build();

处理密码更改策略Handle password change policies

本地帐户注册或登录用户流显示“忘记了密码?” The local account sign-up or sign-in user flow shows a 'Forgot password?' 链接。link. 单击此链接不会自动触发密码重置用户流。Clicking this link doesn't automatically trigger a password reset user flow.

而是会将错误代码 AADB2C90118 返回给应用。Instead, the error code AADB2C90118 is returned to your app. 应用应该通过运行一个可重置密码的特定用户流来处理此错误代码。Your app should handle this error code by running a specific user flow that resets the password.

若要捕获密码重置错误代码,可以在 AuthenticationCallback 中使用以下实现:To catch a password reset error code, the following implementation can be used inside your AuthenticationCallback:

new AuthenticationCallback() {

    @Override
    public void onSuccess(IAuthenticationResult authenticationResult) {
        // ..
    }

    @Override
    public void onError(MsalException exception) {
        final String B2C_PASSWORD_CHANGE = "AADB2C90118";

        if (exception.getMessage().contains(B2C_PASSWORD_CHANGE)) {
            // invoke password reset flow
        }
    }

    @Override
    public void onCancel() {
        // ..
    }
}

使用 IAuthenticationResultUse IAuthenticationResult

成功获取令牌后会生成 IAuthenticationResult 对象。A successful token acquisition results in a IAuthenticationResult object. 该对象包含访问令牌、用户声明和元数据。It contains the access token, user claims, and metadata.

// Get the raw bearer token
String accessToken = authenticationResult.getAccessToken();

// Get the scopes included in the access token
String[] accessTokenScopes = authenticationResult.getScope();

// Gets the access token's expiry
Date expiry = authenticationResult.getExpiresOn();

// Get the tenant for which this access token was issued
String tenantId = authenticationResult.getTenantId();

获取已获授权的帐户Get the authorized account

// Get the account from the result
IAccount account = authenticationResult.getAccount();

// Get the id of this account - note for B2C, the policy name is a part of the id
String id = account.getId();

// Get the IdToken Claims
//
// For more information about B2C token claims, see reference documentation
// /active-directory-b2c/active-directory-b2c-reference-tokens
Map<String, ?> claims = account.getClaims();

// Get the 'preferred_username' claim through a convenience function
String username = account.getUsername();

// Get the tenant id (tid) claim through a convenience function
String tenantId = account.getTenantId();

IdToken 声明IdToken claims

IdToken 中返回的声明由安全令牌服务 (STS) 而不是 MSAL 填充。Claims returned in the IdToken are populated by the Security Token Service (STS), not by MSAL. 根据所用的标识提供者 (IdP),可能缺少某些声明。Depending on the identity provider (IdP) used, some claims may be absent. 某些 IdP 目前不提供 preferred_username 声明。Some IdPs don't currently provide the preferred_username claim. 由于 MSAL 将此声明用于缓存,因此,已使用一个占位符值 MISSING FROM THE TOKEN RESPONSE 来代替此声明。Because this claim is used by MSAL for caching, a placeholder value, MISSING FROM THE TOKEN RESPONSE, is used in its place. 有关 B2C IdToken 声明的详细信息,请参阅 Azure Active Directory B2C 中的令牌概述For more information on B2C IdToken claims, see Overview of tokens in Azure Active Directory B2C.

管理帐户和策略Managing accounts and policies

B2C 将每个策略视为单独的颁发机构。B2C treats each policy as a separate authority. 因此,从每个策略返回的访问令牌、刷新令牌和 ID 令牌不可换用。Thus the access tokens, refresh tokens, and ID tokens returned from each policy are not interchangeable. 这意味着,每个策略将返回单独的 IAccount 对象,该对象的令牌不可用于调用其他策略。This means each policy returns a separate IAccount object whose tokens can't be used to invoke other policies.

每个策略将 IAccount 添加到每个用户的缓存。Each policy adds an IAccount to the cache for each user. 如果用户登录到应用程序并调用两个策略,他们会收到两个 IAccountIf a user signs in to an application and invokes two policies, they'll have two IAccounts. 若要从缓存中删除此用户,必须对每个策略调用 removeAccount()To remove this user from the cache, you must call removeAccount() for each policy.

使用 acquireTokenSilent 续订策略的令牌时,请将以前调用策略后返回的相同 IAccount 提供给 AcquireTokenSilentParametersWhen you renew tokens for a policy with acquireTokenSilent, provide the same IAccount that was returned from previous invocations of the policy to AcquireTokenSilentParameters. 提供另一个策略返回的帐户会导致错误。Providing an account returned by another policy will result in an error.

后续步骤Next steps

若要详细了解 Azure Active Directory B2C (Azure AD B2C),请参阅什么是 Azure Active Directory B2C?Learn more about Azure Active Directory B2C (Azure AD B2C) at What is Azure Active Directory B2C?