You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Azure B2C自定义策略中支持OIDC地址JSON声明并映射内置属性?

解决方案:在Azure B2C自定义策略中支持OIDC标准地址JSON声明

我来帮你搞定这两个Azure B2C自定义策略里的OIDC地址声明问题——这确实是自定义策略中容易卡壳的地方,毕竟默认的声明都是扁平结构,而OIDC标准要求address是嵌套的JSON对象。核心思路是用Azure B2C的ClaimsTransformation功能,把多个内置扁平属性(比如city、postalCode)组合成符合标准的嵌套JSON声明。

1. 核心原理

Azure B2C提供了两个关键的ClaimsTransformation方法来构建JSON:

  • CreateJson:创建一个空的JSON字符串声明
  • AddJsonClaim:将指定的输入声明添加到已有的JSON字符串中,指定嵌套字段名

通过组合这两个方法,我们可以把多个扁平属性逐步组装成OIDC标准的address JSON对象。

2. 具体实现步骤

步骤1:声明所需的内置属性和address JSON声明

首先在<ClaimsSchema>里确保你需要用到的内置属性(比如city、postalCode)已存在,并新增一个address声明来存储最终的JSON字符串:

<ClaimsSchema>
  <!-- 这些内置属性通常已存在,确保DataType正确 -->
  <ClaimType Id="city">
    <DisplayName>City</DisplayName>
    <DataType>string</DataType>
  </ClaimType>
  <ClaimType Id="postalCode">
    <DisplayName>Postal Code</DisplayName>
    <DataType>string</DataType>
  </ClaimType>
  <ClaimType Id="country">
    <DisplayName>Country</DisplayName>
    <DataType>string</DataType>
  </ClaimType>
  <ClaimType Id="streetAddress">
    <DisplayName>Street Address</DisplayName>
    <DataType>string</DataType>
  </ClaimType>
  <!-- 定义存储JSON字符串的address声明 -->
  <ClaimType Id="address">
    <DisplayName>Address</DisplayName>
    <DataType>string</DataType>
  </ClaimType>
</ClaimsSchema>

步骤2:创建ClaimsTransformation来构建address JSON

在<ClaimsTransformations>节点中定义一系列转换,先创建空JSON,再逐个添加属性:

<ClaimsTransformations>
  <!-- 初始化空的address JSON对象 -->
  <ClaimsTransformation Id="createAddressJson" TransformationMethod="CreateJson">
    <OutputClaims>
      <OutputClaim ClaimTypeReferenceId="address" TransformationClaimType="createdJson" />
    </OutputClaims>
  </ClaimsTransformation>

  <!-- 将city映射到address.locality -->
  <ClaimsTransformation Id="addCityToAddress" TransformationMethod="AddJsonClaim">
    <InputClaims>
      <InputClaim ClaimTypeReferenceId="city" TransformationClaimType="inputClaim" />
      <InputClaim ClaimTypeReferenceId="address" TransformationClaimType="existingJson" />
    </InputClaims>
    <InputParameters>
      <InputParameter Id="claimName" DataType="string" Value="locality" />
    </InputParameters>
    <OutputClaims>
      <OutputClaim ClaimTypeReferenceId="address" TransformationClaimType="outputJson" />
    </OutputClaims>
  </ClaimsTransformation>

  <!-- 将postalCode映射到address.postal_code -->
  <ClaimsTransformation Id="addPostalCodeToAddress" TransformationMethod="AddJsonClaim">
    <InputClaims>
      <InputClaim ClaimTypeReferenceId="postalCode" TransformationClaimType="inputClaim" />
      <InputClaim ClaimTypeReferenceId="address" TransformationClaimType="existingJson" />
    </InputClaims>
    <InputParameters>
      <InputParameter Id="claimName" DataType="string" Value="postal_code" />
    </InputParameters>
    <OutputClaims>
      <OutputClaim ClaimTypeReferenceId="address" TransformationClaimType="outputJson" />
    </OutputClaims>
  </ClaimsTransformation>

  <!-- 将country映射到address.country -->
  <ClaimsTransformation Id="addCountryToAddress" TransformationMethod="AddJsonClaim">
    <InputClaims>
      <InputClaim ClaimTypeReferenceId="country" TransformationClaimType="inputClaim" />
      <InputClaim ClaimTypeReferenceId="address" TransformationClaimType="existingJson" />
    </InputClaims>
    <InputParameters>
      <InputParameter Id="claimName" DataType="string" Value="country" />
    </InputParameters>
    <OutputClaims>
      <OutputClaim ClaimTypeReferenceId="address" TransformationClaimType="outputJson" />
    </OutputClaims>
  </ClaimsTransformation>

  <!-- 将streetAddress映射到address.street_address -->
  <ClaimsTransformation Id="addStreetToAddress" TransformationMethod="AddJsonClaim">
    <InputClaims>
      <InputClaim ClaimTypeReferenceId="streetAddress" TransformationClaimType="inputClaim" />
      <InputClaim ClaimTypeReferenceId="address" TransformationClaimType="existingJson" />
    </InputClaims>
    <InputParameters>
      <InputParameter Id="claimName" DataType="string" Value="street_address" />
    </InputParameters>
    <OutputClaims>
      <OutputClaim ClaimTypeReferenceId="address" TransformationClaimType="outputJson" />
    </OutputClaims>
  </ClaimsTransformation>
</ClaimsTransformations>

步骤3:在用户旅程中执行这些转换

创建一个专门的TechnicalProfile来执行上述转换,然后在用户旅程的合适步骤(比如登录/注册完成后,发行Token前)调用它:

<!-- 定义执行地址转换的TechnicalProfile -->
<TechnicalProfile Id="BuildAddressClaim">
  <DisplayName>Build Address JSON Claim</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <OutputClaimsTransformations>
    <OutputClaimsTransformation ReferenceId="createAddressJson" />
    <OutputClaimsTransformation ReferenceId="addCityToAddress" />
    <OutputClaimsTransformation ReferenceId="addPostalCodeToAddress" />
    <OutputClaimsTransformation ReferenceId="addCountryToAddress" />
    <OutputClaimsTransformation ReferenceId="addStreetToAddress" />
  </OutputClaimsTransformations>
</TechnicalProfile>

<!-- 在用户旅程中调用这个TechnicalProfile -->
<UserJourney Id="SignUpOrSignIn">
  <OrchestrationSteps>
    <!-- 省略其他步骤:登录、注册、验证等 -->
    <OrchestrationStep Order="7" Type="ClaimsExchange">
      <ClaimsExchanges>
        <ClaimsExchange Id="BuildAddress" TechnicalProfileReferenceId="BuildAddressClaim" />
      </ClaimsExchanges>
    </OrchestrationStep>
    <!-- 后续步骤:发行Token -->
  </OrchestrationSteps>
</UserJourney>

步骤4:在RelyingParty中输出address声明

最后在<RelyingParty>节点的OutputClaims中添加address声明,这样它就会以JSON对象的形式出现在ID Token中:

<RelyingParty>
  <DefaultUserJourney ReferenceId="SignUpOrSignIn" />
  <TechnicalProfile Id="PolicyProfile">
    <DisplayName>PolicyProfile</DisplayName>
    <Protocol Name="OpenIdConnect" />
    <OutputClaims>
      <OutputClaim ClaimTypeReferenceId="displayName" />
      <OutputClaim ClaimTypeReferenceId="givenName" />
      <OutputClaim ClaimTypeReferenceId="surname" />
      <OutputClaim ClaimTypeReferenceId="email" />
      <!-- 输出address声明 -->
      <OutputClaim ClaimTypeReferenceId="address" />
      <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
      <OutputClaim ClaimTypeReferenceId="identityProvider" />
    </OutputClaims>
    <SubjectNamingInfo ClaimType="sub" />
  </TechnicalProfile>
</RelyingParty>

3. 处理空属性的优化技巧

如果某些属性可能为空,你可以给ClaimsTransformation添加条件,只有当属性存在时才添加到JSON中,避免出现null值:

<ClaimsTransformation Id="addCityToAddress" TransformationMethod="AddJsonClaim">
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="city" TransformationClaimType="inputClaim" />
    <InputClaim ClaimTypeReferenceId="address" TransformationClaimType="existingJson" />
  </InputClaims>
  <InputParameters>
    <InputParameter Id="claimName" DataType="string" Value="locality" />
    <InputParameter Id="ifExists" DataType="string" Value="DoNotOverride" />
  </InputParameters>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="address" TransformationClaimType="outputJson" />
  </OutputClaims>
  <!-- 只有当city声明存在时才执行此转换 -->
  <Conditions>
    <Condition Type="ClaimExists" ExecuteActionsIf="true">
      <Value>city</Value>
    </Condition>
  </Conditions>
</ClaimsTransformation>

完成以上配置后,ID Token中的address字段就会完全符合OIDC标准,格式如下:

"address": {
  "locality": "Seattle",
  "postal_code": "98101",
  "country": "US",
  "street_address": "123 Main St"
}

内容的提问来源于stack exchange,提问作者Eli Pulsifer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:48:35