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

非UI交互模式下无法从B2C自定义策略获取login_hint/domain_hint

问题:非UI交互模式下无法获取B2C自定义策略的login_hint/domain_hint参数

通过UI应用捕获邮箱后,向B2C自定义策略发起携带login_hint=xyz@abc.com和domain_hint=abc.com的请求,需要读取这两个参数并根据domain_hint路由对应的OrchestrationStep,但策略内始终无法获取到这两个值,导致Google-OIDC步骤总是被执行。已知使用带UI的api.selfasserted定义时可正常读取查询字符串值,但无UI交互时无法读取。

请求URL示例:

https://mydomain.b2clogin.com/mydomain.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1A_A_A_G_TEST&client_id=xxxxxxxx-aaaa-aaaa-aaaa-xxxxxxxxxx&nonce=defaultNonce&redirect_uri=https%3A%2F%2Fjwt.ms&scope=openid&response_type=id_token&prompt=login&login_hint=test@gmail.com&domain_hint=gmail.com

现有策略的问题分析

  1. 依赖UI组件的技术Profile:使用SelfAssertedAttributeProvider作为域名提取的技术Profile,该Provider需要用户交互,非UI模式下无法执行,导致email和domain claim无法生成。
  2. 未直接映射domain_hint:未将请求中的domain_hint参数直接映射到策略内的claim,而是通过login_hint提取域名,既冗余又依赖UI。
  3. 预条件逻辑错误:当前预条件设置为当domain等于gmail.com时跳过Google步骤,与期望的"匹配域名时执行该步骤"逻辑相反。

修正后的策略方案

核心修改点

  • 在RelyingParty的TechnicalProfile中直接映射login_hint和domain_hint到对应的claim
  • 使用无UI的ClaimsTransformation技术Profile处理域名提取(若需要从login_hint提取域名的场景)
  • 修正预条件逻辑,确保匹配域名时执行对应的IdP步骤

完整修正后的策略XML

<?xml version="1.0" encoding="utf-8"?>
<TrustFrameworkPolicy
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
  PolicySchemaVersion="0.3.0.0"
  TenantId="MyDomain.onmicrosoft.com"
  PolicyId="B2C_1A_A_A_G_Test"
  PublicPolicyUri="http://MyDomain.onmicrosoft.com/B2C_1A_A_A_G_Test">

  <BasePolicy>
    <TenantId>MyDomain.onmicrosoft.com</TenantId>
    <PolicyId>B2C_1A_TrustFrameworkBase</PolicyId>
  </BasePolicy>

  <BuildingBlocks>
    <ClaimsSchema>
      <ClaimType Id="email">
        <DisplayName>Email</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
      <ClaimType Id="domain">
        <DisplayName>Email Domain</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
    </ClaimsSchema>
    <ClaimsTransformations> 
      <ClaimsTransformation Id="ExtractDomainFromEmail" TransformationMethod="ParseDomain">
        <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" TransformationClaimType="emailAddress" />
        </InputClaims>
        <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="domain" TransformationClaimType="domain" />
        </OutputClaims>
      </ClaimsTransformation>
    </ClaimsTransformations>
  </BuildingBlocks>

  <ClaimsProviders>
    <!-- 无UI的Claims Transformation Profile -->
    <ClaimsProvider>
      <DisplayName>Domain Extractor</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="Extract-Domain-From-Email">
          <DisplayName>Extract Domain</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="domain" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="ExtractDomainFromEmail" />
          </OutputClaimsTransformations>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

    <!-- Google OIDC IdP -->
    <ClaimsProvider>
      <Domain>google.com</Domain>
      <DisplayName>Google</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="Google-OIDC">
          <DisplayName>Google</DisplayName>
          <Protocol Name="OpenIdConnect" />
          <Metadata>
            <Item Key="ProviderName">google</Item>
            <Item Key="authorization_endpoint">https://accounts.google.com/o/oauth2/auth</Item>
            <Item Key="AccessTokenEndpoint">https://accounts.google.com/o/oauth2/token</Item>
            <Item Key="ClaimsEndpoint">https://www.googleapis.com/oauth2/v1/userinfo</Item>
            <Item Key="client_id">client_id_formygoogle</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="client_secret" StorageReferenceId="B2C_1A_GoogleSecret" />
          </CryptographicKeys>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
          </OutputClaims>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
  </ClaimsProviders>

  <UserJourneys>
    <UserJourney Id="SignUpOrSignInaa">
      <OrchestrationSteps>
        <!-- 步骤1:提取域名(可选,若直接用domain_hint可跳过此步骤) -->
        <OrchestrationStep Order="1" Type="ClaimsExchange">
          <Preconditions>
            <!-- 如果domain_hint已存在,跳过提取步骤 -->
            <Precondition Type="ClaimExists" ExecuteActionsIf="true">
              <Value>domain</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="ExtractDomain" TechnicalProfileReferenceId="Extract-Domain-From-Email" />
          </ClaimsExchanges>
        </OrchestrationStep>

        <!-- 步骤2:匹配domain为gmail.com时执行Google登录 -->
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
              <Value>domain</Value>
              <Value>gmail.com</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="IdP-Google" TechnicalProfileReferenceId="Google-OIDC" />
          </ClaimsExchanges>
        </OrchestrationStep>

        <!-- 步骤3:颁发令牌 -->
        <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
      </OrchestrationSteps>
      <ClientDefinition ReferenceId="DefaultWeb" />
    </UserJourney>
  </UserJourneys>

  <RelyingParty>
    <DefaultUserJourney ReferenceId="SignUpOrSignInaa" />
    <TechnicalProfile Id="PolicyProfile">
      <DisplayName>PolicyProfile</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <InputClaims>
        <!-- 直接映射login_hint和domain_hint到策略内的claim -->
        <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="login_hint" />
        <InputClaim ClaimTypeReferenceId="domain" PartnerClaimType="domain_hint" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="email" />
      </OutputClaims>
      <SubjectNamingInfo ClaimType="email" />
    </TechnicalProfile>
  </RelyingParty>
</TrustFrameworkPolicy>

关键说明

  1. 直接映射参数:在RelyingParty的InputClaims中添加domain与domain_hint的映射,无需额外提取即可直接获取该参数值。
  2. 无UI的技术Profile:将域名提取的技术Profile的Handler改为ClaimsTransformationProtocolProvider,该组件无需用户交互,可在非UI模式下执行。
  3. 修正预条件:将预条件改为当domain不等于gmail.com时跳过Google步骤,确保匹配时执行该IdP流程。
  4. 可选的提取步骤:添加预条件判断,如果domain已经通过domain_hint传入,则跳过从login_hint提取域名的步骤,提升效率。

内容的提问来源于stack exchange,提问作者Senthil Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 08:29:51