MIT License

技术解读

以下内容由 GitRead 中文社区 编辑团队基于项目 README 与官方资料整理, 结合中文开发者的常见使用场景补充技术选型建议。具体以项目官方文档为准。

Azure-Samples/active-directory-b2c-custom-policy-starterpack 技术深度分析

项目背景与痛点

当涉及到用户身份管理,Azure AD B2C 提供了一个用户友好的解决方案,允许用户通过各种认证方式登录应用。然而,随着业务需求的多样化,Azure AD B2C 的标准策略只能满足基础需求。对于那些期望定制化认证流程的企业来说,复杂的需求无法仅通过标准策略实现。因此,Azure 提供了自定义策略的方式,这允许用户拥有更高的控制度和灵活性。

该仓库 Azure-Samples/active-directory-b2c-custom-policy-starterpack 正是为了填补这一空白,帮助开发者快速构建高度定制化认证流程,以解决业务的特定需求。

核心技术揭秘

自定义策略的核心在于配置文件的设计,这些配置文件定义了用户身份验证的各个方面,包括认证流程、属性转换和存储。这些策略文件通过 XML 格式定义,涵盖了认证流程的所有关键点。

在架构层面,该仓库提供了一个自定义策略的骨架,包括多个不同的策略配置文件,如用户注册、登录、密码重置等。通过 XML 配置,覆盖了一片复杂的用户身份管理和交互行为。

graph TD A[用户请求] --> B{"参数校验"} B -->|"通过"| C[执行业务] C --> D[调用 Identity Experience Framework] D --> E{"策略决策"} E -->|"用户注册"| F[注册流程] E -->|"用户登录"| G[登录流程] E -->|"属性处理"| H[属性转换] F --> I[用户数据存储] G --> J[会话创建] H --> K[数据持久化] I --> L[返回注册结果] J --> M[返回登录结果] K --> N[返回转换结果]

通过 Mermaid 图的描述,可以清晰地看出自定义策略的执行流程:

  • 用户请求 : 外部请求触发认证流程。
  • 参数校验 : 首先检查请求参数是否正确。
  • 执行业务 : 如果参数校验通过,进入下一步的业务逻辑。
  • 调用 Identity Experience Framework : 业务执行后,调用 Identity Experience Framework 处理用户身份数据。
  • 策略决策 : 根据请求类型,决定后续步骤(如用户注册、登录等)。
  • 注册流程 : 当请求为注册时,进入注册流程,处理注册相关逻辑。
  • 登录流程 : 当请求为登录时,进入登录流程,处理登录逻辑。
  • 属性处理 : 在每次流程中,都会有数据属性转换过程。
  • 数据存储 : 最终将用户数据存储,处理后返回结果。

功能亮点与差异

与标准策略相比,自定义策略可以赋予开发者在用户管理流程上有更大的自由度。比如,更灵活的注册和登录流程、复杂的属性处理逻辑,甚至可以与外部服务(如短信验证)进行集成。

该仓库提供的骨架文件,针对常见的认证场景如注册、登录和各种身份数据处理,都有详细的注释和配置指南,非常适合开发者快速上手。

与其他同类产品相比,自定义策略提供了更为深入的配置能力和模块化的设计思想,可以在最小的改动下满足多种规格的认证需求。

应用场景与落地建议

该仓库适合于需要高度定制化用户体验的企业应用场景,例如大规模 SaaS 产品、政府系统、银行平台等。

在生产环境中使用时,需要关注策略文件的复杂性管理,合理维护,避免配置文件的膨胀和臃肿。同时,应持续关注 Azure AD B2C 和 Identity Experience Framework 的官方更新和安全防护措施。

综合评价

优点:

  • 提供标准化与高度可配置的用户认证和管理,适合大规模定制化应用。
  • 提供详细的示例和配置说明,减少了开发学习曲线,适合初学者快速掌握。
  • 具有丰富的扩展能力,支持集成多种外部服务。

缺点:

  • 配置文件随着业务需求增加会变得复杂,增加了维护的难度。
  • 高度配置灵活性意味着更高的学习成本,对于新手来说,上手不易。

总体来看,Azure-Samples/active-directory-b2c-custom-policy-starterpack 为开发者提供了一个强大的工具集,对于那些对身份管理有更高要求的项目来说,不失为一个上佳之选。

关于

GitHub 原始描述(英文)

Azure AD B2C now allows uploading of a Custom Policy which allows full control and customization of the Identity Experience Framework

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

简要分析

热度分
1514
价值分
366
活跃状态
活跃

README

Contributing

This project has adopted the Microsoft Open Source Code of Conduct. For more information, see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

Change log

09 August 2022

With this version the starter pack now contains a Refresh Token user journey. This journey will be executed any time an application refreshes a token. It will check the user still exists and is enabled in the Azure AD B2C directory. It also checks that the refresh token is not expired. It compiles any claims that are not persisted in the user profile, including claims from Identity Provider’s and REST API calls. A new set of refreshed tokens is then issued.

This fix allows for refresh token to be revoked from users and prevents directory deleted users from getting continued access.Change affects all starterpack samples.

Policy Notes
B2C_1A_TrustFrameworkBase Added Refresh Token claims, Refresh Token ClaimsTransformations, Refresh Token Technical Profiles and Refresh Token User Journey
B2C_1A_SignUpOrSignIn Added Refresh Token Endpoint to Relying Party

Migrate existing policy to this version

Your custom policy can invoke a custom refresh token journey. Add the following user journey to your TrustFrameworkExtensions.xml file to get started.

  1. Open the extensions file of your policy. For example, SocialAndLocalAccounts/TrustFrameworkExtensions.xml.
  2. Locate the UserJourneys element. If the element doesn’t exist, add it.
  3. Add the following UserJourney to the UserJourneys element.
<!--
<UserJourneys>-->
  <UserJourney Id="RedeemRefreshToken">
    <PreserveOriginalAssertion>false</PreserveOriginalAssertion>
    <OrchestrationSteps>
      <OrchestrationStep Order="1" Type="ClaimsExchange">
        <ClaimsExchanges>
          <ClaimsExchange Id="RefreshTokenSetupExchange" TechnicalProfileReferenceId="RefreshTokenReadAndSetup" />
        </ClaimsExchanges>
      </OrchestrationStep>
      <OrchestrationStep Order="2" Type="ClaimsExchange">
        <ClaimsExchanges>
          <ClaimsExchange Id="CheckRefreshTokenDateFromAadExchange" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId-CheckRefreshTokenDate" />
        </ClaimsExchanges>
      </OrchestrationStep>
      <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
    </OrchestrationSteps>
  </UserJourney>
<!--
</UserJourneys>-->

This user journey will validate that the refresh token has not been revoked. You can revoke refresh tokens in Azure AD B2C following the Microsoft Graph API Revoke sign in sessions guidance.

You can add additional steps into this journey to call any other technical profiles, such as to your REST API technical profiles or Azure AD read/write technical profiles.

Configure the relying party policy

The relying party file must be configured to point to your custom refresh token journey. This allows Azure AD B2C to reference your refresh token journey when your app makes a refresh token request.

Add an Endpoint with Id set to token and provide a UserJourneyReferenceId referencing the UserJourney Id from the prior section. Merge the following XML snippet into your SignUpOrSignin.xml file.

<RelyingParty> 
  <DefaultUserJourney ReferenceId="SignUpOrSignIn" /> 
    <Endpoints> 
      <Endpoint Id="Token" UserJourneyReferenceId="RedeemRefreshToken" /> 
    </Endpoints>
    ...    
</RelyingParty> 

Repeat this for all Relying party files your application may invoke, such as ProfileEdit.xml and PasswordReset.xml.

Configure refresh token revocation evaluation

The custom refresh token journey can be used to evaluate whether the current refresh token being presented has been revoked. To implement this logic, Azure AD B2C must compare the refreshTokenIssuedOnDateTime and the refreshTokensValidFromDateTime. Create the claims schema definitions as shown in the below XML snippet in your TrustFrameworkExtensions.xml.

  1. Open the extensions file of your policy. For example, SocialAndLocalAccounts/TrustFrameworkExtensions.xml.
  2. Locate the BuildingBlocks element. If the element doesn’t exist, add it.
  3. Locate the ClaimsSchema element. If the element doesn’t exist, add it.
  4. Add the following claims to the ClaimsSchema element.
<!--
<BuildingBlocks>
  <ClaimsSchema> -->
    <ClaimType Id="refreshTokenIssuedOnDateTime">
      <DisplayName>refreshTokenIssuedOnDateTime</DisplayName>
      <DataType>string</DataType>
      <AdminHelpText>Used to determine if the user should be permitted to reauthenticate silently via their existing refresh token.</AdminHelpText>
      <UserHelpText>Used to determine if the user should be permitted to reauthenticate silently via their existing refresh token.</UserHelpText>
    </ClaimType>
    <ClaimType Id="refreshTokensValidFromDateTime">
      <DisplayName>refreshTokensValidFromDateTime</DisplayName>
      <DataType>string</DataType>
      <AdminHelpText>Used to determine if the user should be permitted to reauthenticate silently via their existing refresh token.</AdminHelpText>
      <UserHelpText>Used to determine if the user should be permitted to reauthenticate silently via their existing refresh token.</UserHelpText>
    </ClaimType>
  <!--
  </ClaimsSchema>
</BuildingBlocks> -->

To check whether the refresh token has been revoked, the refreshTokenIssuedOnDateTime and the refreshTokensValidFromDateTime must be compared. Add the following AssertDateTimeIsGreaterThan ClaimsTransformation to your TrustFrameworkExtensions.xml.

  1. Open the extensions file of your policy. For example, SocialAndLocalAccounts/TrustFrameworkExtensions.xml.
  2. Locate the BuildingBlocks element. If the element doesn’t exist, add it.
  3. Locate the ClaimsTransformations element. If the element doesn’t exist, add it.
  4. Add the following ClaimsTransformation to the ClaimsTransformations element.
<!--
<BuildingBlocks>
  <ClaimsTransformations> -->
    <ClaimsTransformation Id="AssertRefreshTokenIssuedLaterThanValidFromDate" TransformationMethod="AssertDateTimeIsGreaterThan">
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="refreshTokenIssuedOnDateTime" TransformationClaimType="leftOperand" />
        <InputClaim ClaimTypeReferenceId="refreshTokensValidFromDateTime" TransformationClaimType="rightOperand" />
      </InputClaims>
      <InputParameters>
        <InputParameter Id="AssertIfEqualTo" DataType="boolean" Value="false" />
        <InputParameter Id="AssertIfRightOperandIsNotPresent" DataType="boolean" Value="true" />
        <InputParameter Id="TreatAsEqualIfWithinMillseconds" DataType="int" Value="300000" />
      </InputParameters>
    </ClaimsTransformation>
  <!--
  </ClaimsTransformations>
</BuildingBlocks> -->

To invoke the process to evaluate whether the refresh token has been revoked, add the following technical profile to your TrustFrameworkExtensions.xml.

  1. Open the extensions file of your policy. For example, SocialAndLocalAccounts/TrustFrameworkExtensions.xml.
  2. Locate the ClaimsProviders element. If the element doesn’t exist, add it.
  3. Add the following ClaimsProvider to the ClaimsProviders element.
  4. Add extra claims collected from previous REST API’s and Federated IDP’s that have not been persisted in the directory as OutputClaims under the RefreshTokenReadAndSetup technical profile
<!--
<ClaimsProviders> -->
  <ClaimsProvider>
    <DisplayName>Refresh token journey</DisplayName>
    <TechnicalProfiles>
      <TechnicalProfile Id="RefreshTokenReadAndSetup">
        <DisplayName>Trustframework Policy Engine Refresh Token Setup Technical Profile</DisplayName>
        <Protocol Name="None" />
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="objectId" />
          <OutputClaim ClaimTypeReferenceId="refreshTokenIssuedOnDateTime" />
              <!--additional claims from REST API or Federated IDP-->
            <OutputClaim ClaimTypeReferenceId="ExtraClaim1" />
            <OutputClaim ClaimTypeReferenceId="ExtraClaim2" />
        </OutputClaims>
      </TechnicalProfile>
      <TechnicalProfile Id="AAD-UserReadUsingObjectId-CheckRefreshTokenDate">
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="refreshTokensValidFromDateTime" />
        </OutputClaims>
        <OutputClaimsTransformations>
          <OutputClaimsTransformation ReferenceId="AssertRefreshTokenIssuedLaterThanValidFromDate" />
        </OutputClaimsTransformations>
        <IncludeTechnicalProfile ReferenceId="AAD-UserReadUsingObjectId" />
      </TechnicalProfile>
    </TechnicalProfiles>
  </ClaimsProvider>
<!--
</ClaimsProviders> -->
Upload the policies
  1. Select the Identity Experience Framework menu item in your B2C tenant in the Azure portal.
  2. Select Upload custom policy
  3. Select Overwrite the custom policy if it already exists
  4. In this order, upload the policy files:
    1. TrustFrameworkExtensions.xml
    2. SignUpOrSignin.xml

11 October 2021

With this version the starter pack now contains localization policy file TrustFrameworkLocalization.xml. The localization policy allows your policy to accommodate different languages to suit your customer needs. For more information, check the PR #107.

The new localization policy is located between the base and the extension policies:

Policy Base policy Notes
B2C_1A_TrustFrameworkBase Contains most of the definitions. To help with troubleshooting and long-term maintenance of your policies, try to minimize the number of changes you make to this file.
B2C_1A_TrustFrameworkLocalization B2C_1A_TrustFrameworkBase Holds the localization strings.
B2C_1A_TrustFrameworkExtensions B2C_1A_TrustFrameworkLocalization Holds the unique configuration changes for your tenant.
Relying Parties (RP) B2C_1A_TrustFrameworkExtensions For example: sign-up, sign-in, password reset, or profile edit.

Migrate exiting policy to this version

To migrate from the older version of the starter pack to this version:

  1. Download the starter pack and update the tenant name.

  2. Upload the newer version of TrustFrameworkBase.xml file.

  3. Upload the new TrustFrameworkLocalization.xml file.

  4. Update your existing TrustFrameworkExtension.xml with the new base policy B2C_1A_TrustFrameworkLocalization. The following XML snippet demonstrates the base policy before the change:

    <!-- file: TrustFrameworkExtensions.xml -->
    <BasePolicy>
      <TenantId>yourtenant.onmicrosoft.com</TenantId>
      <PolicyId>B2C_1A_TrustFrameworkBase</PolicyId>
    </BasePolicy>
    

    The following XML snippet demonstrates the base policy after the change:

    <!-- file: TrustFrameworkExtensions.xml -->
    <BasePolicy>
      <TenantId>yourtenant.onmicrosoft.com</TenantId>
      <PolicyId>B2C_1A_TrustFrameworkLocalization</PolicyId>
    </BasePolicy>
    
  5. Upload the TrustFrameworkExtension.xml policy.

15 September 2021

Update to the content definition page version. With the new version the starter pack uses the page contract. For more information, see Migrating to page layout.

20 July 2019

Updated policies to use the new Ocean Blue template

29 January 2019

A collection of bugfixes, improvements to code, and additional feature support is included in this starterpack. It is not necessary or encouraged for developers to change policies currently in production or in testing. We do encourage the use of these new versions for all new projects.

10 May 2017

Public Preview Release

5 May 2017

Added Key definition to the metadata element in all four TrustframeworkBase.xml versions. When this Item Key is set to TRUE, the expiration dates on the token issued by B2C will be presented as JSON Numbers. When set to False (default) they will be presented as strings.

<Item Key="SendTokenResponseBodyWithJsonNumbers">true</Item> 

Important notes

The following Change is incorporated into the latest version of starterpack (01/29/2019) - It remains here for historical purposes. 06/26/2017 - Correction to SocialAndLocalAccountswMFA in TrustFrameworkBase.xml file.

A change to fix a data loss issue related to SSO, the profile edit policy, and MFA. This issue was due to the MFA SSO technical profile not outputting the below claim in the same format that the regular MFA provider does

<TechnicalProfile Id="SM-MFA">
  <DisplayName>Session Mananagement Provider</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.SSO.DefaultSSOSessionProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <PersistedClaims>
***OLD:  <PersistedClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" />
***CORRECTED:  <PersistedClaim ClaimTypeReferenceId="Verified.strongAuthenticationPhoneNumber" />
    <PersistedClaim ClaimTypeReferenceId="executed-PhoneFactor-Input" />
  </PersistedClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="isActiveMFASession" DefaultValue="true" />
  </OutputClaims>
</TechnicalProfile>

评论

暂无评论