Azure B2C自定义SAML策略声明配置失效及按应用配置诉求
我来帮你梳理下问题所在,以及具体的解决步骤——Azure B2C自定义策略下的SAML声明配置和常规Azure AD确实不一样,核心是自定义策略完全接管了声明的生成和发送逻辑,应用注册里的配置基本不起作用,得按策略规则来。
1. 先确认:你的声明有没有被填充值?
这是最容易忽略的点——Azure B2C不会在SAML响应中发送空值的声明。如果你只定义了ClaimType和OutputClaim,但这个TESTFELDSTRING没有被赋值,它肯定不会出现在响应里。
你需要根据业务场景给声明赋值:
- 从用户目录属性读取:如果这个值存在于B2C用户目录的扩展属性中,要在读取用户信息的TechnicalProfile(比如
AAD-UserReadUsingObjectId)里添加输出声明,映射到目录属性:<TechnicalProfile Id="AAD-UserReadUsingObjectId"> <!-- 其他配置 --> <OutputClaims> <!-- 原有声明 --> <OutputClaim ClaimTypeReferenceId="TESTFELDSTRING" PartnerClaimType="extension_TESTFELDSTRING" /> </OutputClaims> </TechnicalProfile> - 通过用户输入获取:如果需要用户在登录/注册时填写这个字段,要在用户旅程的自断言步骤(比如
SelfAsserted-LocalAccountSignin-Email)里添加输入声明:<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email"> <!-- 其他配置 --> <InputClaims> <InputClaim ClaimTypeReferenceId="TESTFELDSTRING" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="TESTFELDSTRING" /> </OutputClaims> </TechnicalProfile> - 通过声明转换生成:如果需要从现有声明拼接/转换得到这个值,要先定义
ClaimsTransformation,再在对应的TechnicalProfile里调用它。
2. 正确配置RelyingParty和SAML Issuer
在你的自定义策略(比如SignUpOrSignIn.xml)的<RelyingParty>节点下,确保OutputClaims包含你的声明:
<RelyingParty> <DefaultUserJourney ReferenceId="SignUpOrSignIn" /> <TechnicalProfile Id="PolicyProfile"> <DisplayName>PolicyProfile</DisplayName> <Protocol Name="SAML2" /> <OutputClaims> <!-- 原有声明 --> <OutputClaim ClaimTypeReferenceId="TESTFELDSTRING" /> </OutputClaims> <!-- 其他配置 --> </TechnicalProfile> </RelyingParty>
这里的PolicyProfile是直接对接SAML应用的技术配置文件,只要声明有值,就会被包含在SAML响应里。
3. 实现"按应用配置不同声明"的需求
这对应你提到的常规Azure AD里的功能,在B2C自定义策略中,你可以给每个SAML应用创建独立的RelyingParty策略文件:
- 每个应用对应一个单独的策略(比如
ContosoApp-SignUpSignIn.xml、FabrikamApp-SignUpSignIn.xml) - 在各自的
OutputClaims里定义该应用需要的声明,不需要的就不添加 - 给每个应用分配对应的策略作为登录端点即可
这种方式完全隔离了不同应用的声明配置,和Azure AD的应用级声明配置逻辑一致。
4. 关于应用注册的optionalClaims
划重点:自定义策略模式下,应用注册清单里的optionalClaims是无效的。因为自定义策略完全覆盖了B2C的声明生成流程,所有声明都要在策略里配置,不用管应用注册里的设置。
5. 额外:调整SAML声明的格式(如果需要)
如果你的应用期望特定的声明名称格式(比如URI格式的Name),可以修改ClaimType里的SAML协议配置:
<ClaimType Id="TESTFELDSTRING"> <DisplayName>TESTFELDSTRING</DisplayName> <DataType>string</DataType> <DefaultPartnerClaimTypes> <Protocol Name="OpenIdConnect" PartnerClaimType="TESTFELDSTRING" /> <Protocol Name="SAML2" PartnerClaimType="http://your-custom-namespace/claims/TESTFELDSTRING" /> </DefaultPartnerClaimTypes> <UserHelpText>Your TESTFELDSTRING name.</UserHelpText> <UserInputType>TextBox</UserInputType> </ClaimType>
这样SAML响应里的声明Name就会变成你指定的URI,同时可以在OutputClaim里添加FriendlyName:
<OutputClaim ClaimTypeReferenceId="TESTFELDSTRING" FriendlyName="TESTFELDSTRING" />
最后:调试建议
可以用SAML Tracer这类浏览器插件捕获SAML响应,直观查看声明是否存在;也可以在B2C自定义策略里启用调试模式,查看声明在用户旅程各步骤中的流动情况,确认TESTFELDSTRING在到达SAML Issuer步骤时已经有值。
内容的提问来源于stack exchange,提问作者Robin

