Azure ad b2c 无法在Azure AD B2C自定义策略中查询自定义REST API

Azure ad b2c 无法在Azure AD B2C自定义策略中查询自定义REST API,azure-ad-b2c,Azure Ad B2c,我试图在新用户通过创建自定义Azure AD B2C自定义策略注册时调用我们的REST API。我尝试将调用添加到API中,既可以作为验证配置文件(如中所述),也可以作为用户旅程(如中所述) 这两种方案我都无法实现。在这两种情况下,我都会收到以下错误,“AADB2C90027:为“REST API注册”指定的基本凭据无效。请检查凭据是否正确,以及资源是否已授予访问权限。” 当我使用Application Insights并将对API的调用添加为用户输入的验证时,我看到抛出了“类型为“Web.TP

我试图在新用户通过创建自定义Azure AD B2C自定义策略注册时调用我们的REST API。我尝试将调用添加到API中,既可以作为验证配置文件(如中所述),也可以作为用户旅程(如中所述)

这两种方案我都无法实现。在这两种情况下,我都会收到以下错误,“AADB2C90027:为“REST API注册”指定的基本凭据无效。请检查凭据是否正确,以及资源是否已授予访问权限。

当我使用Application Insights并将对API的调用添加为用户输入的验证时,我看到抛出了“类型为“Web.TPEngine.Providers.BadArgumentRetryNeededException”的异常。”在其他堆栈溢出帖子中,我发现,
BadArgumentRetryNeededException
IdentityExperienceFramework
ProxyIdentityExperienceFramework
应用程序未正确配置和/或未从一个应用程序向另一个应用程序授予权限相关联。但是,我已经多次验证这些配置是否正确,以及它们是否在
TrustFrameworkExtensions.xml
文件中被正确引用,因此我假设这不是问题所在

我已经测试了在使用和不使用基本身份验证的情况下调用API,并且收到了相同的错误。因此,我还假设API需要基本身份验证的问题是,因为即使API需要身份验证,我也会收到此错误

我将复制下面的一些自定义策略


来自TrustFrameworkExtensions.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="notrealtenantid.onmicrosoft.com"
  PolicyId="B2C_1A_TrustFrameworkExtensions"
  PublicPolicyUri="http://notrealtenantid.onmicrosoft.com/B2C_1A_TrustFrameworkExtensions">

  <BasePolicy>
    <TenantId>notrealtenantid.onmicrosoft.com</TenantId>
    <PolicyId>B2C_1A_TrustFrameworkBase</PolicyId>
  </BasePolicy>
  <BuildingBlocks>
    <ClaimsSchema>
      <ClaimType Id="loyaltyNumber">
        <DisplayName>loyaltyNumber</DisplayName>
        <DataType>string</DataType>
        <UserHelpText>Customer loyalty number</UserHelpText>
      </ClaimType>
    </ClaimsSchema>
  </BuildingBlocks>
  <ClaimsProviders>

    <!-- Local account claims provider -->
    <ClaimsProvider>
      <DisplayName>Local Account SignIn</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="login-NonInteractive">
          <Metadata>
            <!-- ProxyIdentityExperienceFramework -->
            <Item Key="client_id">732c7aec-0080-4421-bdba-cb0a156b596f</Item>
            <!-- IdentityExperienceFramework -->
            <Item Key="IdTokenAudience">e66b1d02-a473-4a1a-8cc2-b5d22da7d92a</Item>
          </Metadata>
          <InputClaims>
            <!-- ProxyIdentityExperienceFramework -->
            <InputClaim ClaimTypeReferenceId="client_id" DefaultValue="732c7aec-0080-4421-bdba-cb0a156b596f" />
            <!-- IdentityExperienceFramework -->
            <InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="e66b1d02-a473-4a1a-8cc2-b5d22da7d92a" />
          </InputClaims>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

    <!-- Facebook claims provider -->
    <ClaimsProvider>
      <DisplayName>Facebook</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="Facebook-OAUTH">
          <Metadata>
            <Item Key="client_id">1234</Item>
            <Item Key="scope">email public_profile</Item>
            <Item Key="ClaimsEndpoint">https://graph.facebook.com/me?fields=id,first_name,last_name,name,email</Item>
          </Metadata>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

    <ClaimsProvider>
      <DisplayName>REST APIs</DisplayName>
      <TechnicalProfiles>

        <!-- Custom Restful service -->
        <TechnicalProfile Id="REST-API-SignUp">
          <DisplayName>Validate user's input data and return loyaltyNumber claim</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ServiceUrl">https://NotRealUrl.com/1/0/usercheck</Item>
            <Item Key="AuthenticationType">None</Item>
            <Item Key="SendClaimsIn">Body</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" />
            <InputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="firstName" />
            <InputClaim ClaimTypeReferenceId="surname" PartnerClaimType="lastName" />
            <InputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="loyaltyNumber" PartnerClaimType="loyaltyNumber" />
          </OutputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>

      </TechnicalProfiles>
    </ClaimsProvider>
  </ClaimsProviders>

  <UserJourneys>
    <UserJourney Id="SignUpOrSignIn">
      <OrchestrationSteps>

        <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
          <ClaimsProviderSelections>
            <ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" />
            <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
          </ClaimsProviderSelections>
          <ClaimsExchanges>
            <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
          </ClaimsExchanges>
        </OrchestrationStep>

        <!-- Check if the user has selected to sign in using one of the social providers -->
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>objectId</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="FacebookExchange" TechnicalProfileReferenceId="Facebook-OAUTH" />
            <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
          </ClaimsExchanges>
        </OrchestrationStep>

        <!-- For social IDP authentication, attempt to find the user account in the directory. -->
        <OrchestrationStep Order="3" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
              <Value>authenticationSource</Value>
              <Value>localAccountAuthentication</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId-NoError" />
          </ClaimsExchanges>
        </OrchestrationStep>

        <!-- Show self-asserted page only if the directory does not have the user account already (i.e. we do not have an objectId). 
          This can only happen when authentication happened using a social IDP. If local account was created or authentication done
          using ESTS in step 2, then an user account must exist in the directory by this time. -->
        <OrchestrationStep Order="4" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>objectId</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="SelfAsserted-Social" TechnicalProfileReferenceId="SelfAsserted-Social" />
          </ClaimsExchanges>
        </OrchestrationStep>

        <!-- This step reads any user attributes that we may not have received when authenticating using ESTS so they can be sent 
          in the token. -->
        <OrchestrationStep Order="5" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
              <Value>authenticationSource</Value>
              <Value>socialIdpAuthentication</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <!-- The previous step (SelfAsserted-Social) could have been skipped if there were no attributes to collect 
             from the user. So, in that case, create the user in the directory if one does not already exist 
             (verified using objectId which would be set from the last step if account was created in the directory. -->
        <OrchestrationStep Order="6" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>objectId</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserWrite" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <!-- Do Rest call.
            NOTE!! Sign up works if this orchestration step is not included. -->
        <OrchestrationStep Order="7" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="GetLoyaltyData" TechnicalProfileReferenceId="REST-API-SignUp" />
          </ClaimsExchanges>
        </OrchestrationStep>

        <OrchestrationStep Order="8" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />

      </OrchestrationSteps>
      <ClientDefinition ReferenceId="DefaultWeb" />
    </UserJourney>

  </UserJourneys>

</TrustFrameworkPolicy>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<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="notrealtenantid.onmicrosoft.com"
  PolicyId="B2C_1A_signup_signin"
  PublicPolicyUri="http://notrealtenantid.onmicrosoft.com/B2C_1A_signup_signin"
  DeploymentMode="Development"
  UserJourneyRecorderEndpoint="urn:journeyrecorder:applicationinsights">

  <BasePolicy>
    <TenantId>notrealtenantid.onmicrosoft.com</TenantId>
    <PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
  </BasePolicy>

  <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" />
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
        <OutputClaim ClaimTypeReferenceId="identityProvider" />
        <OutputClaim ClaimTypeReferenceId="loyaltyNumber" DefaultValue="" />
      </OutputClaims>
      <SubjectNamingInfo ClaimType="sub" />
    </TechnicalProfile>
  </RelyingParty>
</TrustFrameworkPolicy>

如果我注释掉编排步骤7,即调用RESTAPI的步骤,那么注册过程就可以工作了。因此,问题与API的调用无关


是否有人知道是什么原因导致“AADB2C90027:为“REST API注册”指定的基本凭据无效。请检查凭据是否正确,以及资源是否已授予访问权限。”错误?我不知所措,因为API不需要基本身份验证。

经过一些团队讨论后,发现Web应用程序防火墙(WAF)在Azure应用程序网关上配置的是阻止请求并返回403的HTTP响应,因为B2C没有为
用户代理发送HTTP头

该请求在禁用阻止它的WAF规则后工作

已创建功能请求,以便B2C在以下位置发送
用户代理
请求标头:


同时,解决方法是禁用需要
用户代理
头的WAF规则,或者让B2C调用不受WAF保护的API。

确保您的自定义策略中包含应用ID和应用机密。谢谢你,玛丽莉。事实证明,请求实际上被Web应用程序防火墙阻止,因为B2C没有发送
用户代理的HTTP头。