Azure AD B2C:通过密码重置流后无法立即登录



我们创建了一个内置的密码重置用户流。

我们使用Microsoft Graph API在B2C中自动注册用户,并发送一封带有密码重置流程直接链接的电子邮件,以便用户在首次登录时重置密码。

用户正确地通过密码重置用户流,并被重定向回我们的应用程序,该应用程序将用户重定向到我们的SignIn自定义策略用户旅程!

我们有Home Realm Discovery,用户首先会看到一个屏幕,输入他们的电子邮件地址,单击"下一步",然后输入密码。

输入电子邮件地址并单击";下一个";我们得到以下错误:

Sorry, but we're having trouble signing you in.
We track these errors automatically, but if the problem persists feel free to contact us. In the meantime, please try again.
Correlation ID: d5a7e1ed-a6d2-4b6d-bc87-b8612a5419b4
Timestamp: 2021-05-27 12:19:05Z
AADB2C: An exception has occurred.

这是用户旅程和子旅程:

<UserJourneys>
<UserJourney Id="HRDSignUpSignInMFAEmebeddedPasswordReset">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="ParseDomainHint" TechnicalProfileReferenceId="ParseDomainHint" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- api.hrd reference to custom login page / content definition -->
<OrchestrationStep Order="2" Type="ClaimsExchange" ContentDefinitionReferenceId="api.hrd">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>isFederatedAuthentication</Value>
<Value>true</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-Signin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>isFederatedAuthentication</Value>
<Value>False</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="IsKnownCustomerLogic" TechnicalProfileReferenceId="CreateidentityProvidersCollectionLogic" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- The technical profile uses a validation technical profile to authenticate the user. -->
<!--Protocal: Web.TPEngine.Providers.SelfAssertedAttributeProvider Session: SM-AAD=Web.TPEngine.SSO.DefaultSSOSessionProvider -->
<OrchestrationStep Order="4" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signinandsignupwithpassword">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>isFederatedAuthentication</Value>
<Value>true</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
<ClaimsProviderSelection TargetClaimsExchangeId="ForgotPasswordExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Local Email Account Sign Up -->
<!-- Protocol: Web.TPEngine.Providers.SelfAssertedAttributeProvider  Session: SM-AAD="Web.TPEngine.SSO.DefaultSSOSessionProvider -->
<OrchestrationStep Order="5" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>isFederatedAuthentication</Value>
<Value>true</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
<ClaimsExchange Id="ForgotPasswordExchange" TechnicalProfileReferenceId="ForgotPassword" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- If the domain matched any known domain, then this step will have a single IdP
enabled due to each known IdP TP having an enablement flag via identityProviders claim -->
<OrchestrationStep Order="6" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselections">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>isFederatedAuthentication</Value>
<Value>true</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="IDP1OIDC" />
<ClaimsProviderSelection TargetClaimsExchangeId="IDP2SAML" />
</ClaimsProviderSelections>
</OrchestrationStep>
<OrchestrationStep Order="7" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>isFederatedAuthentication</Value>
<Value>true</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="IDP1OIDC" TechnicalProfileReferenceId="IDP1-OIDC-TP" />
<ClaimsExchange Id="IDP2SAML" TechnicalProfileReferenceId="IDP2-SAML-TP" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- If the user clicks on Forgot Password then execute this subjourney - otherwise skip -->
<OrchestrationStep Order="8" Type="InvokeSubJourney">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>isForgotPassword</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<JourneyList>
<Candidate SubJourneyReferenceId="PasswordReset" />
</JourneyList>
</OrchestrationStep>
<!-- For social IDP authentication, attempt to find the user account in the directory. -->
<OrchestrationStep Order="9" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<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>
<OrchestrationStep Order="10" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>objectId</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="11" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>authenticationSource</Value>
<Value>socialIdpAuthentication</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserWrite" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="12" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>isFederatedAuthentication</Value>
<Value>true</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-InputOrVerify" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Save MFA phone number: The precondition verifies whether the user provided a new number in the 
previous step. If so, then the phone number is stored in the directory for future authentication 
requests. -->
<!--References AAD-Common(Web.TPEngine.Providers.AzureActiveDirectoryProvider & SM-Noop) -->
<OrchestrationStep Order="13" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>isFederatedAuthentication</Value>
<Value>true</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>newPhoneNumberEntered</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserWriteWithObjectId" TechnicalProfileReferenceId="AAD-UserWritePhoneNumberUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="14" Type="ClaimsExchange">
<ClaimsExchanges>
<!-- create the emails claim combining signInNames and otherMails -->
<ClaimsExchange Id="AADUserCreateEmailsClaim" TechnicalProfileReferenceId="AAD-UserCreateEmailsClaim" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="15" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
<SubJourneys>
<SubJourney Id="PasswordReset" Type="Call">
<OrchestrationSteps>
<!--Sample: Validate user's email address. Run this step only when user resets the password-->
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="PasswordResetUsingEmailAddressExchange" TechnicalProfileReferenceId="LocalAccountDiscoveryUsingEmailAddress" />
</ClaimsExchanges>
</OrchestrationStep>
<!--Sample: Collect and persist a new password. Run this step only when user resets the password-->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="NewCredentials" TechnicalProfileReferenceId="LocalAccountWritePasswordUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
</OrchestrationSteps>
</SubJourney>
</SubJourneys>

这不是一个完整的答案/修复。

我不知道上面的用户之旅出了什么问题,但根据@JasSuri MSFT在这里写的内容https://github.com/azure-ad-b2c/samples/issues/235错误信息显示:

Claims exchange with id 'LocalAccountSigninEmailExchange' could not be found 
in orchestration step '5' and the step contains more than one claims exchange.

然后我所做的就是将LocalAccountSigninEmailExchange<ClaimExchange>从步骤4移动到步骤5。现在步骤4和5看起来像这样:

<!-- The technical profile uses a validation technical profile to authenticate the user. -->
<!--Protocal: Web.TPEngine.Providers.SelfAssertedAttributeProvider Session: SM-AAD=Web.TPEngine.SSO.DefaultSSOSessionProvider -->
<OrchestrationStep Order="4" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signinandsignupwithpassword">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>isFederatedAuthentication</Value>
<Value>true</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
<ClaimsProviderSelection TargetClaimsExchangeId="ForgotPasswordExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<!-- <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" /> -->
</ClaimsExchanges>
</OrchestrationStep>
<!-- Local Email Account Sign Up -->
<!-- Protocol: Web.TPEngine.Providers.SelfAssertedAttributeProvider  Session: SM-AAD="Web.TPEngine.SSO.DefaultSSOSessionProvider -->
<OrchestrationStep Order="5" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>isFederatedAuthentication</Value>
<Value>true</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
<ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
<ClaimsExchange Id="ForgotPasswordExchange" TechnicalProfileReferenceId="ForgotPassword" />
</ClaimsExchanges>
</OrchestrationStep>

这与Github中的用户指南和B2C示例不同,但由于某种原因,现在它可以工作。也就是说,我的信心很低,因为我不明白为什么,但我想我仍然会和你分享。

最新更新