【发布时间】:2018-08-23 21:26:08
【问题描述】:
我正在尝试通过创建自定义 Azure AD B2C 自定义策略在新用户注册时调用我们的 REST API。我尝试将 API 调用添加为Integrate REST API claims exchanges in your Azure AD B2C user journey as validation of user input 中所述的验证配置文件,以及Walkthrough: Integrate REST API claims exchanges in your Azure AD B2C user journey as an orchestration step 中所述的用户旅程。
我无法让任何一种情况发挥作用。在这两种情况下,我都会收到以下错误:“AADB2C90027:为 'REST-API-SignUp' 指定的基本凭据无效。请检查凭据是否正确以及资源是否已授予访问权限。 "
当我结合使用 Application Insights 并添加对 API 的调用来验证用户输入时,我看到“抛出了 'Web.TPEngine.Providers.BadArgumentRetryNeededException' 类型的异常。”在其他 Stack Overflow 帖子,我看到 BadArgumentRetryNeededException 与未正确配置的 IdentityExperienceFramework 和 ProxyIdentityExperienceFramework 应用程序相关联和/或未从一个应用程序授予另一个应用程序的权限。但是,我已经多次验证这些配置正确,并且它们在TrustFrameworkExtensions.xml 文件中被正确引用,所以我认为这不是问题。
我已经测试了在使用和不使用基本身份验证的情况下调用 API,我收到了同样的错误。因此,我还假设问题不是与需要基本身份验证的 API 相关,因为即使 API 需要 no 身份验证,我也会收到此错误。
我将复制下面的一些自定义政策。
来自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>
来自SignUpOrSignin.xml的代码:
<?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,这是调用我们的 REST API 的步骤,那么注册过程就会起作用。因此,问题与 API 的调用有关。
有谁知道可能导致“AADB2C90027:为“REST-API-SignUp”指定的基本凭据无效。请检查凭据是否正确以及资源是否已授予访问权限。”错误?我不知所措,因为 API 不需要需要基本身份验证。
【问题讨论】:
-
确保您的自定义策略中包含 App ID 和 App Secret。 github.com/MicrosoftDocs/azure-docs/blob/master/articles/…
-
谢谢你,玛丽莉。事实证明,该请求实际上被 Web 应用程序防火墙阻止,因为 B2C 没有发送
User-Agent的 HTTP 标头。
标签: azure-ad-b2c