3

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

我们使用 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.

这是 UserJourney 和 SubJourney:

<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>
4

1 回答 1

0

不是完整的答案/修复。

我不知道上面的用户旅程有什么问题,但根据@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.

然后我所做的就是将<ClaimExchange>forLocalAccountSigninEmailExchange从第 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 示例不同,但由于某种原因,它现在可以工作了。也就是说,我的信心很低,因为我不明白为什么,但我还是想和你分享。

于 2021-06-08T15:48:59.587 回答