你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用 Azure Active Directory B2C 设置通过 LinkedIn 帐户注册与登录

开始之前,可以使用“选择策略类型”选择器来选择要设置的策略类型。 Azure Active Directory B2C 提供了两种定义用户如何与应用程序交互的方法:通过预定义的用户流,或者通过可完全配置的自定义策略。 对于每种方法,本文中所需的步骤都不同。

注意

在 Azure Active Directory B2C 中,自定义策略主要用于解决复杂的情况。 在大多数情况下,建议你使用内置用户流。 如果尚未这样做,请从 Active Directory B2C 中的自定义策略入门了解自定义策略新手包。

必备条件

创建 LinkedIn 应用程序

若要在 Azure Active Directory B2C (Azure AD B2C) 中为使用 LinkedIn 帐户的用户启用登录,你需要在 LinkedIn 开发人员网站中创建应用程序。 有关详细信息,请参阅授权代码流。 如果你没有 LinkedIn 帐户,可在 https://www.linkedin.com/ 上注册一个。

  1. 使用 LinkedIn 帐户凭据登录到 LinkedIn 开发人员网站
  2. 选择“我的应用”,然后单击“创建应用”。
  3. 输入应用名称LinkedIn 页隐私策略 URL应用徽标
  4. 同意 LinkedIn 的“API 使用条款”并单击“创建应用”。
  5. 选择“身份验证”选项卡。在“身份验证密钥”下,复制“客户端 ID”和“客户端密码”的值。 将 LinkedIn 配置为租户中的标识提供者时需要这两个值。 “客户端密钥”是一个很重要的安全凭据。
  6. 选择“应用的授权重定向 URL”旁边的编辑铅笔,然后选择“添加重定向 URL”。 输入 https://your-tenant-name.b2clogin.com/your-tenant-name.onmicrosoft.com/oauth2/authresp。 如果使用自定义域,请输入 https://your-domain-name/your-tenant-name.onmicrosoft.com/oauth2/authresp。 将 your-tenant-name 替换为租户的名称,将 your-domain-name 替换为你的自定义域。 输入租户名称时,必须全部使用小写字母,即使租户是使用大写字母在 Azure AD B2C 中定义的,也是如此。 选择“更新”。
  7. 默认情况下,LinkedIn 应用未获准使用与登录相关的作用域。 若要请求评审,请选择“产品”选项卡,然后选择“使用 LinkedIn 登录”。 评审完成后,所需作用域会添加到你的应用程序。

    注意

    可以在“OAuth 2.0 作用域”部分的“身份验证”选项卡上查看目前允许应用使用的作用域。

将 LinkedIn 配置为标识提供者

  1. 以 Azure AD B2C 租户的全局管理员身份登录 Azure 门户
  2. 如果有权访问多个租户,请选择顶部菜单中的“设置”图标,从“目录 + 订阅”菜单切换到你的 Azure AD B2C 租户。
  3. 选择 Azure 门户左上角的“所有服务”,搜索并选择 Azure AD B2C
  4. 选择“标识提供者”,然后选择“LinkedIn”
  5. 输入“名称”。 例如 LinkedIn
  6. 对于“客户端 ID”,请输入前面创建的 LinkedIn 应用程序的客户端 ID
  7. 对于“客户端密码”,请输入已记录的客户端密码。
  8. 选择“保存”。

将 LinkedIn 标识提供者添加到用户流

此时,LinkedIn 标识提供者已设置,但还不能在任何登录页中使用。 将 LinkedIn 标识提供者添加到用户流:

  1. 在 Azure AD B2C 租户中,选择“用户流” 。
  2. 单击要添加 LinkedIn 标识提供者的用户流。
  3. 在“社交标识提供者”下,选择“LinkedIn”。
  4. 选择“保存”。
  5. 若要测试策略,请选择“运行用户流”。
  6. 对于“应用程序”,请选择前面已注册的名为“testapp1”的 Web 应用程序。 “回复 URL”应显示为 https://jwt.ms
  7. 选择“运行用户流”按钮。
  8. 在注册或登录页面上,选择“LinkedIn”以使用 LinkedIn 帐户登录。

如果登录过程是成功的,则你的浏览器会被重定向到 https://jwt.ms,其中显示 Azure AD B2C 返回的令牌内容。

创建策略密钥

你需要存储前面在 Azure AD B2C 租户中记录的客户端机密。

  1. 登录 Azure 门户
  2. 如果有权访问多个租户,请选择顶部菜单中的“设置”图标,切换到“目录 + 订阅”菜单中的 Azure AD B2C 租户。
  3. 选择 Azure 门户左上角的“所有服务”,然后搜索并选择“Azure AD B2C” 。
  4. 在“概述”页上选择“标识体验框架”。
  5. 选择“策略密钥”,然后选择“添加”。
  6. 对于“选项”,请选择 Manual
  7. 输入策略密钥的名称。 例如,LinkedInSecret。 前缀“B2C_1A_”会自动添加到密钥名称中。
  8. 在“机密”中,输入前面记录的客户端密码。
  9. 在“密钥用法”处选择 Signature
  10. 单击“创建”。

将 LinkedIn 配置为标识提供者

若要允许用户使用 LinkedIn 帐户登录,需将该帐户定义为 Azure AD B2C 可通过终结点与其进行通信的声明提供程序。 该终结点将提供一组声明,Azure AD B2C 使用这些声明来验证特定的用户是否已完成身份验证。

通过在策略的扩展文件中将 LinkedIn 帐户添加到 ClaimsProvider 元素,将该帐户定义为声明提供程序。

  1. 在编辑器中,打开 SocialAndLocalAccounts/TrustFrameworkExtensions.xml 文件。 此文件位于自定义策略初学者包中,你已将其作为必备组件之一的一部分下载。

  2. 找到 ClaimsProviders 元素。 如果该元素不存在,请在根元素下添加它。

  3. 如下所示添加新的 ClaimsProvider

    <ClaimsProvider>
      <Domain>linkedin.com</Domain>
      <DisplayName>LinkedIn</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="LinkedIn-OAuth2">
          <DisplayName>LinkedIn</DisplayName>
          <Protocol Name="OAuth2" />
          <Metadata>
            <Item Key="ProviderName">linkedin</Item>
            <Item Key="authorization_endpoint">https://www.linkedin.com/oauth/v2/authorization</Item>
            <Item Key="AccessTokenEndpoint">https://www.linkedin.com/oauth/v2/accessToken</Item>
            <Item Key="ClaimsEndpoint">https://api.linkedin.com/v2/me</Item>
            <Item Key="scope">r_emailaddress r_liteprofile</Item>
            <Item Key="HttpBinding">POST</Item>
            <Item Key="external_user_identity_claim_id">id</Item>
            <Item Key="BearerTokenTransmissionMethod">AuthorizationHeader</Item>
            <Item Key="ResolveJsonPathsInJsonTokens">true</Item>
            <Item Key="UsePolicyInRedirectUri">false</Item>
            <Item Key="client_id">Your LinkedIn application client ID</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="client_secret" StorageReferenceId="B2C_1A_LinkedInSecret" />
          </CryptographicKeys>
          <InputClaims />
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="id" />
            <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="firstName.localized" />
            <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="lastName.localized" />
            <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="linkedin.com" AlwaysUseDefaultValue="true" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" AlwaysUseDefaultValue="true" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="ExtractGivenNameFromLinkedInResponse" />
            <OutputClaimsTransformation ReferenceId="ExtractSurNameFromLinkedInResponse" />
            <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
            <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
            <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
            <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />
          </OutputClaimsTransformations>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    
  4. client_id 的值替换为你之前记录的 LinkedIn 应用程序的客户端 ID。

  5. 保存文件。

添加声明转换

LinkedIn 技术配置文件要求将 ExtractGivenNameFromLinkedInResponse 和 ExtractSurNameFromLinkedInResponse 声明转换添加到 ClaimsTransformations 列表。 如果未在文件中定义 ClaimsTransformations 元素,请添加父 XML 元素,如下所示。 声明转换还需要定义一个名为“nullStringClaim”的新声明类型。

BuildingBlocks 元素添加到 TrustFrameworkExtensions.xml 文件顶部附近。 有关示例,请参阅 TrustFrameworkBase.xml。

<BuildingBlocks>
  <ClaimsSchema>
    <!-- Claim type needed for LinkedIn claims transformations -->
    <ClaimType Id="nullStringClaim">
      <DisplayName>nullClaim</DisplayName>
      <DataType>string</DataType>
      <AdminHelpText>A policy claim to store output values from ClaimsTransformations that aren't useful. This claim should not be used in TechnicalProfiles.</AdminHelpText>
      <UserHelpText>A policy claim to store output values from ClaimsTransformations that aren't useful. This claim should not be used in TechnicalProfiles.</UserHelpText>
    </ClaimType>
  </ClaimsSchema>

  <ClaimsTransformations>
    <!-- Claim transformations needed for LinkedIn technical profile -->
    <ClaimsTransformation Id="ExtractGivenNameFromLinkedInResponse" TransformationMethod="GetSingleItemFromJson">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="givenName" TransformationClaimType="inputJson" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="nullStringClaim" TransformationClaimType="key" />
        <OutputClaim ClaimTypeReferenceId="givenName" TransformationClaimType="value" />
      </OutputClaims>
    </ClaimsTransformation>
    <ClaimsTransformation Id="ExtractSurNameFromLinkedInResponse" TransformationMethod="GetSingleItemFromJson">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="surname" TransformationClaimType="inputJson" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="nullStringClaim" TransformationClaimType="key" />
        <OutputClaim ClaimTypeReferenceId="surname" TransformationClaimType="value" />
      </OutputClaims>
    </ClaimsTransformation>
  </ClaimsTransformations>
</BuildingBlocks>

添加用户旅程

此时,标识提供者已设置,但还不能在任何登录页中使用。 如果你没有自己的自定义用户旅程,请创建现有模板用户旅程的副本,否则,请继续执行下一步。

  1. 打开初学者包中的 TrustFrameworkBase.xml 文件。
  2. 找到并复制包含 Id="SignUpOrSignIn"UserJourney 元素的完整内容。
  3. 打开 TrustFrameworkExtensions.xml 并找到 UserJourneys 元素。 如果该元素不存在,请添加一个。
  4. 将复制的 UserJourney 元素的完整内容粘贴为 UserJourneys 元素的子级。
  5. 对用户旅程的 ID 进行重命名。 例如,Id="CustomSignUpSignIn"

将标识提供者添加到用户旅程

目前你已拥有用户旅程,请将新的标识提供者添加到用户旅程。 首先添加一个“登录”按钮,然后将该按钮链接到某个操作。 该操作是你之前创建的技术配置文件。

  1. 在用户旅程中,查找包含 Type="CombinedSignInAndSignUp"Type="ClaimsProviderSelection" 的业务流程步骤元素。 这通常是第一个业务流程步骤。 ClaimsProviderSelections 元素包含用户可以用来登录的标识提供者列表。 元素的顺序将决定向用户显示的登录按钮的顺序。 添加 ClaimsProviderSelection XML 元素。 将 TargetClaimsExchangeId 的值设置为易记名称。

  2. 在下一个业务流程步骤中,添加 ClaimsExchange 元素。 将 ID 设置为目标声明交换 ID 的值。将 TechnicalProfileReferenceId 的值更新为之前创建的技术配置文件的 ID 。

下面的 XML 演示了使用标识提供者进行用户旅程的前两个业务流程步骤:

<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
  <ClaimsProviderSelections>
    ...
    <ClaimsProviderSelection TargetClaimsExchangeId="LinkedInExchange" />
  </ClaimsProviderSelections>
  ...
</OrchestrationStep>

<OrchestrationStep Order="2" Type="ClaimsExchange">
  ...
  <ClaimsExchanges>
    <ClaimsExchange Id="LinkedInExchange" TechnicalProfileReferenceId="LinkedIn-OAuth2" />
  </ClaimsExchanges>
</OrchestrationStep>

配置信赖方策略

信赖方策略(例如 SignUpSignIn.xml)指定 Azure AD B2C 将执行的用户旅程。 在信赖方内查找 DefaultUserJourney 元素。 更新 ReferenceId,使其与已在其中添加标识提供者的用户旅程 ID 匹配。

在以下示例中,对于 CustomSignUpSignIn 用户旅程,将 ReferenceId 设置为 CustomSignUpSignIn

<RelyingParty>
  <DefaultUserJourney ReferenceId="CustomSignUpSignIn" />
  ...
</RelyingParty>

上传自定义策略

  1. 登录 Azure 门户
  2. 在门户工具栏中选择“目录 + 订阅”图标,然后选择包含 Azure AD B2C 租户的目录。
  3. 在 Azure 门户中,搜索并选择“Azure AD B2C”。
  4. 在“策略”下,选择“Identity Experience Framework”。
  5. 选择“上传自定义策略”,然后上传已更改的两个策略文件,其顺序为:先上传扩展策略(例如 TrustFrameworkExtensions.xml),然后上传信赖方策略(例如 SignUpSignIn.xml)。

测试自定义策略

  1. 选择信赖方策略,例如 B2C_1A_signup_signin
  2. 对于“应用程序”,请选择前面注册的 Web 应用程序。 “回复 URL”应显示为 https://jwt.ms
  3. 选择“立即运行”按钮。
  4. 在注册或登录页面上,选择“LinkedIn”以使用 LinkedIn 帐户登录。

如果登录过程是成功的,则你的浏览器会被重定向到 https://jwt.ms,其中显示 Azure AD B2C 返回的令牌内容。

从 v1.0 迁移到 v2.0

LinkedIn 最近已将其 API 从 v1.0 更新到 v2.0。 若要将现有配置迁移到新配置,请根据以下部分的信息更新技术配置文件中的元素。

替换 Metadata 中的项

TechnicalProfile 的现有 Metadata 元素中,更新以下项中的下列 Item 元素:

<Item Key="ClaimsEndpoint">https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address,headline)</Item>
<Item Key="scope">r_emailaddress r_basicprofile</Item>

更改为:

<Item Key="ClaimsEndpoint">https://api.linkedin.com/v2/me</Item>
<Item Key="scope">r_emailaddress r_liteprofile</Item>

向 Metadata 添加项

TechnicalProfileMetadata 中,添加以下 Item 元素:

<Item Key="external_user_identity_claim_id">id</Item>
<Item Key="BearerTokenTransmissionMethod">AuthorizationHeader</Item>
<Item Key="ResolveJsonPathsInJsonTokens">true</Item>

更新 OutputClaims

TechnicalProfile 的现有 OutputClaims 中,更新以下项中的下列 OutputClaim 元素:

<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="firstName" />
<OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="lastName" />

更改为:

<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="firstName.localized" />
<OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="lastName.localized" />

添加新的 OutputClaimsTransformation 元素

TechnicalProfileOutputClaimsTransformations 中,添加以下 OutputClaimsTransformation 元素:

<OutputClaimsTransformation ReferenceId="ExtractGivenNameFromLinkedInResponse" />
<OutputClaimsTransformation ReferenceId="ExtractSurNameFromLinkedInResponse" />

定义新的声明转换和声明类型

在上一个步骤中,你添加了需要定义的新声明转换。 若要定义声明转换,请将它们添加到 ClaimsTransformations 列表中。 如果未在文件中定义 ClaimsTransformations 元素,请添加父 XML 元素,如下所示。 声明转换还需要定义一个名为“nullStringClaim”的新声明类型。

应将 BuildingBlocks 元素添加到文件顶部附近。 请将 TrustframeworkBase.xml 作为示例查看。

<BuildingBlocks>
  <ClaimsSchema>
    <!-- Claim type needed for LinkedIn claims transformations -->
    <ClaimType Id="nullStringClaim">
      <DisplayName>nullClaim</DisplayName>
      <DataType>string</DataType>
      <AdminHelpText>A policy claim to store unuseful output values from ClaimsTransformations. This claim should not be used in a TechnicalProfiles.</AdminHelpText>
      <UserHelpText>A policy claim to store unuseful output values from ClaimsTransformations. This claim should not be used in a TechnicalProfiles.</UserHelpText>
    </ClaimType>
  </ClaimsSchema>

  <ClaimsTransformations>
    <!-- Claim transformations needed for LinkedIn technical profile -->
    <ClaimsTransformation Id="ExtractGivenNameFromLinkedInResponse" TransformationMethod="GetSingleItemFromJson">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="givenName" TransformationClaimType="inputJson" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="nullStringClaim" TransformationClaimType="key" />
        <OutputClaim ClaimTypeReferenceId="givenName" TransformationClaimType="value" />
      </OutputClaims>
    </ClaimsTransformation>
    <ClaimsTransformation Id="ExtractSurNameFromLinkedInResponse" TransformationMethod="GetSingleItemFromJson">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="surname" TransformationClaimType="inputJson" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="nullStringClaim" TransformationClaimType="key" />
        <OutputClaim ClaimTypeReferenceId="surname" TransformationClaimType="value" />
      </OutputClaims>
    </ClaimsTransformation>
  </ClaimsTransformations>
</BuildingBlocks>

获取电子邮件地址

在将 LinkedIn 从 v1.0 迁移到 v2.0 的过程中,需要再次调用另一个 API 才能获得电子邮件地址。 如果需要在注册过程中获取电子邮件地址,请执行以下操作:

  1. 完成上述步骤以允许 Azure AD B2C 与 LinkedIn 联合,这样用户就能登录。 在联合身份验证过程中,Azure AD B2C 会接收 LinkedIn 的访问令牌。

  2. 将 LinkedIn 访问令牌保存到声明中。 请参阅此处的说明

  3. 添加以下可向 LinkedIn 的 /emailAddress API 发出请求的声明提供程序。 若要针对此请求授权,需要 LinkedIn 访问令牌。

    <ClaimsProvider>
      <DisplayName>REST APIs</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="API-LinkedInEmail">
          <DisplayName>Get LinkedIn email</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
              <Item Key="ServiceUrl">https://api.linkedin.com/v2/emailAddress?q=members&amp;projection=(elements*(handle~))</Item>
              <Item Key="AuthenticationType">Bearer</Item>
              <Item Key="UseClaimAsBearerToken">identityProviderAccessToken</Item>
              <Item Key="SendClaimsIn">Url</Item>
              <Item Key="ResolveJsonPathsInJsonTokens">true</Item>
          </Metadata>
          <InputClaims>
              <InputClaim ClaimTypeReferenceId="identityProviderAccessToken" />
          </InputClaims>
          <OutputClaims>
              <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="elements[0].handle~.emailAddress" />
          </OutputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    
  4. 将以下业务流程步骤添加到用户旅程,以便在用户使用 LinkedIn 登录时触发 API 声明提供程序。 请确保相应地更新 Order 号。 紧接着可触发 LinkedIn 技术配置文件的业务流程步骤添加此步骤。

    <!-- Extra step for LinkedIn to get the email -->
    <OrchestrationStep Order="3" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimsExist" ExecuteActionsIf="false">
          <Value>identityProvider</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
        <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
          <Value>identityProvider</Value>
          <Value>linkedin.com</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="GetEmail" TechnicalProfileReferenceId="API-LinkedInEmail" />
      </ClaimsExchanges>
    </OrchestrationStep>
    

在注册期间从 LinkedIn 获取电子邮件地址的操作是可选的。 如果你选择不从 LinkedIn 获取电子邮件,但要求用户在注册过程中提供一个,则用户需要手动输入电子邮件地址并对其进行验证。

如果需要通过完整的示例来了解某个使用 LinkedIn 标识提供者的策略,请参阅自定义策略初学者包

从 v1.0 迁移到 v2.0

LinkedIn 最近已将其 API 从 v1.0 更新到 v2.0。 在迁移过程中,Azure AD B2C 只能获取 LinkedIn 用户在注册期间提供的全名。 如果电子邮件地址是注册期间收集的属性之一,则用户必须手动输入该电子邮件地址并对其进行验证。