Azure B2C自定义策略中无法读取Salesforce OpenID的custom_attributes声明
问题:Azure B2C自定义策略读取Salesforce的custom_attributes声明失败
场景与现象
- Salesforce作为身份提供商(IDP),Azure B2C通过OpenID协议对接,其他声明均可正常读取,但无法读取
custom_attributes声明。经C#应用验证,Salesforce已正确返回该属性:"custom_attributes": { "customername": "ABC" } - 在B2C自定义策略的OutputClaims中配置
custom_attributes后,登录弹窗提示AADB2C: An exception has occurred.,尝试使用OutputClaimsTransformation仍出现相同异常。 - 怀疑原因:
custom_attributes为JSON对象格式,但Azure B2C的ClaimType无对应数据类型;测试发现若给custom_attributes设置默认值,ClaimTransformation可正常工作。
相关配置
Technical Profile
<TechnicalProfile Id="Salesforce-OpenIdConnect"> <DisplayName>Salesforce</DisplayName> <Protocol Name="OpenIdConnect" /> <Metadata> <Item Key="METADATA">openidcofig meatadata path</Item> <Item Key="response_types">code</Item> <Item Key="response_mode">form_post</Item> <Item Key="scope">openid id profile email</Item> <Item Key="issuer">issuer</Item> <Item Key="HttpBinding">POST</Item> <Item Key="UsePolicyInRedirectUri">0</Item> <!-- Update the Client ID below to the Application ID --> <Item Key="client_id">clientid</Item> </Metadata> <CryptographicKeys> <Key Id="client_secret" StorageReferenceId="B2C_1A_Secret"/> </CryptographicKeys> <OutputClaims> <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="sub" /> <OutputClaim ClaimTypeReferenceId="identityUrl" PartnerClaimType="aud" /> <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" /> <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="family_name" /> <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" /> <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" /> <OutputClaim ClaimTypeReferenceId="custom_attributes" /> <OutputClaim ClaimTypeReferenceId="identityProvider" PartnerClaimType="iss" /> <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" AlwaysUseDefaultValue="true" /> </OutputClaims> <OutputClaimsTransformations> <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" /> <OutputClaimsTransformation ReferenceId="GetCustomerNameClaimFromJson" /> <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" /> <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" /> </OutputClaimsTransformations> <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" /> </TechnicalProfile>
Claim Type
<ClaimType Id="custom_attributes"> <DisplayName>custom_attributes</DisplayName> <DataType>string</DataType> <DefaultPartnerClaimTypes> <Protocol Name="OpenIdConnect" PartnerClaimType="custom_attributes" /> </DefaultPartnerClaimTypes> </ClaimType>
Claim Transformation
<ClaimsTransformation Id="GetCustomerNameClaimFromJson" TransformationMethod="GetClaimFromJson"> <InputClaims> <InputClaim ClaimTypeReferenceId="custom_attributes" TransformationClaimType="inputJson" /> </InputClaims> <InputParameters> <InputParameter Id="claimToExtract" DataType="string" Value="customername" /> </InputParameters> <OutputClaims> <OutputClaim ClaimTypeReferenceId="customername" TransformationClaimType="extractedClaim" /> </OutputClaims> </ClaimsTransformation>
User Journey
<UserJourney Id="CustomSignUpSignIn"> <OrchestrationSteps> <!-- For social IDP authentication, attempt to find the user account in the directory. --> <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin"> <ClaimsProviderSelections> <ClaimsProviderSelection TargetClaimsExchangeId="SalesforceExchange" /> </ClaimsProviderSelections> </OrchestrationStep> <!-- Show self-asserted page only if the directory does not have the user account already (i.e. we do not have an objectId). --> <OrchestrationStep Order="2" Type="ClaimsExchange"> <Preconditions> <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> <Value>objectId</Value> <Action>SkipThisOrchestrationStep</Action> </Precondition> </Preconditions> <ClaimsExchanges> <ClaimsExchange Id="SalesforceExchange" TechnicalProfileReferenceId="Salesforce-OpenIdConnect" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" /> </OrchestrationSteps> <ClientDefinition ReferenceId="DefaultWeb" /> </UserJourney>
解决方案
方法1:直接提取嵌套字段(推荐)
由于custom_attributes是JSON对象,直接映射会导致B2C无法序列化,因此可以跳过整个对象的映射,直接提取嵌套的customername字段:
- 添加
customername的ClaimType定义:
<ClaimType Id="customername"> <DisplayName>Customer Name</DisplayName> <DataType>string</DataType> </ClaimType>
修改
Salesforce-OpenIdConnect技术配置的OutputClaims:- 移除
<OutputClaim ClaimTypeReferenceId="custom_attributes" /> - 添加:
<OutputClaim ClaimTypeReferenceId="customername" PartnerClaimType="custom_attributes.customername" />
- 移除
移除
GetCustomerNameClaimFromJson相关的OutputClaimsTransformation配置,因为不再需要从JSON中提取字段。
方法2:获取完整JSON对象并转换(若需完整对象)
如果必须获取整个custom_attributes对象,需确保B2C能将JSON对象转为字符串:
- 保持
custom_attributes的ClaimType为string,修改技术配置的Metadata,添加:
<Item Key="ExtractClaimsFromJson">true</Item>
该配置会让B2C将嵌套的JSON对象序列化为字符串后存入Claim。
- 保留原有的
GetCustomerNameClaimFromJson转换配置,即可从字符串中提取customername。
额外检查
- 确认Salesforce已将
custom_attributes字段加入ID Token的返回范围,必要时调整Salesforce应用的权限配置,确保对应scope已被授权。 - 启用Azure B2C的Application Insights日志,查看具体异常信息,定位问题根源。
内容的提问来源于stack exchange,提问作者Santa N
相关产品推荐
相关产品推荐

