尝试在访问令牌中包含自定义声明时出现验证错误

Validation errors when trying to include custom claims in access token

我为 Azure AD B2C 的自定义策略苦苦挣扎。我的政策基于 jit-migration-v2 文件:https://github.com/azure-ad-b2c/user-migration/tree/master/jit-migration-v2

我添加了 4 个新的自定义属性并将它们包含在 TrustFrameworkExtension.xml 文件中:extension_creditorIdextension_likvidoUserIdextension_likvidoRoleextension_title

这是我的完整 TrustFrameworkExtension.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="{Settings:Tenant}" PolicyId="B2C_1A_JITMigraion_TrustFrameworkExtensions" PublicPolicyUri="http://{Settings:Tenant}/B2C_1A_JITMigraion_TrustFrameworkExtensions">

  <BasePolicy>
    <TenantId>{Settings:Tenant}</TenantId>
    <PolicyId>B2C_1A_JITMigraion_TrustFrameworkBase</PolicyId>
  </BasePolicy>
  <BuildingBlocks>
    <ClaimsSchema>
      <!--Demo: This claim indicates whether the user need to migrate-->
      <ClaimType Id="needToMigrate">
        <DisplayName>needToMigrate</DisplayName>
        <DataType>string</DataType>
        <AdminHelpText>Indicates whether the user need to migrate</AdminHelpText>
        <UserHelpText>Indicates whether the user need to migrate</UserHelpText>
      </ClaimType>
      <ClaimType Id="useInputPassword">
        <DisplayName>useInputPassword</DisplayName>
        <DataType>boolean</DataType>
      </ClaimType>

      <ClaimType Id="extension_creditorId">
        <DisplayName>Creditor ID</DisplayName>
        <DataType>int</DataType>
        <AdminHelpText>The ID of the creditor this user belongs to</AdminHelpText>
        <UserHelpText>The ID of the creditor this user belongs to</UserHelpText>
      </ClaimType>
      <ClaimType Id="extension_likvidoUserId">
        <DisplayName>Likvido user ID</DisplayName>
        <DataType>string</DataType>
        <AdminHelpText>The ID of the user in the Likvido DB</AdminHelpText>
        <UserHelpText>The ID of the user in the Likvido DB</UserHelpText>
      </ClaimType>
      <ClaimType Id="extension_likvidoRole">
        <DisplayName>Likvido user role</DisplayName>
        <DataType>string</DataType>
        <AdminHelpText>The role of the user in Likvido</AdminHelpText>
        <UserHelpText>The role of the user in Likvido</UserHelpText>
      </ClaimType>
      <ClaimType Id="extension_title">
        <DisplayName>Likvido user title</DisplayName>
        <DataType>string</DataType>
        <AdminHelpText>The title of the user</AdminHelpText>
        <UserHelpText>The title of the user</UserHelpText>
      </ClaimType>
    </ClaimsSchema>
  </BuildingBlocks>

  <ClaimsProviders>
    <ClaimsProvider>
      <DisplayName>Azure Active Directory</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="AAD-Common">
          <Metadata>
            <!--Insert b2c-extensions-app application ID here, for example: 11111111-1111-1111-1111-111111111111-->  
            <Item Key="ClientId">{Settings:B2CExtensionsAppClientId}</Item>
            <!--Insert b2c-extensions-app application ObjectId here, for example: 22222222-2222-2222-2222-222222222222-->
            <Item Key="ApplicationObjectId">{Settings:B2CExtensionsAppObjectId}</Item>
          </Metadata>
        </TechnicalProfile>
      </TechnicalProfiles> 
    </ClaimsProvider>
    <!-- Local account Sign-Up claims provider -->
    <ClaimsProvider>
      <DisplayName>Local Account</DisplayName>
      <TechnicalProfiles>

        <!-- SIGN-IN -->
        <TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="needToMigrate" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <!--Demo: Add user migration validation technical profile before login-NonInteractive -->
            <ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-SignIn" ContinueOnError="false" />

            <!--Demo: Run this validation technical profile only if user doesn't need to migrate -->
            <ValidationTechnicalProfile ReferenceId="login-NonInteractive">
              <Preconditions>
                <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                  <Value>needToMigrate</Value>
                  <Value>local</Value>
                  <Action>SkipThisValidationTechnicalProfile</Action>
                </Precondition>
              </Preconditions>
            </ValidationTechnicalProfile>

            <!--Demo: Run this validation technical profile only if user needs to migrate -->
            <ValidationTechnicalProfile ReferenceId="AAD-MigrateUserUsingLogonEmail">
              <Preconditions>
                <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
                  <Value>needToMigrate</Value>
                  <Value>local</Value>
                  <Action>SkipThisValidationTechnicalProfile</Action>
                </Precondition>
              </Preconditions>
            </ValidationTechnicalProfile>

          </ValidationTechnicalProfiles>
        </TechnicalProfile>

        <!-- SIGN-UP -->
        <TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
          <Metadata>
            <Item Key="EnforceEmailVerification">False</Item>
          </Metadata>
          <ValidationTechnicalProfiles>
            <!--Demo: Add user migration validation technical profile before AAD-UserWriteUsingLogonEmail -->
            <ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-SignUp" ContinueOnError="false" />
            <ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" ContinueOnError="false" />
          </ValidationTechnicalProfiles>
        </TechnicalProfile>

        <!-- PASSWORD RESET first page -->
        <TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
          <Metadata>
            <Item Key="EnforceEmailVerification">False</Item>
          </Metadata>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" ContinueOnError="true" />
            <ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-PasswordReset1" ContinueOnError="false" />
          </ValidationTechnicalProfiles>
        </TechnicalProfile>

        <!-- PASSWORD RESET second page -->
        <TechnicalProfile Id="LocalAccountWritePasswordUsingObjectId">
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="AAD-UserWritePasswordUsingObjectId">
              <!--Don't run this validation technical profile if objectId is not exists (migrated acccount)-->
              <Preconditions>
                <Precondition Type="ClaimsExist" ExecuteActionsIf="false">
                  <Value>objectId</Value>
                  <Action>SkipThisValidationTechnicalProfile</Action>
                </Precondition>
              </Preconditions>
            </ValidationTechnicalProfile>

            <ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-PasswordReset2">
              <!--Don't run this validation technical profile if objectId is exists (existing acccount)-->
              <Preconditions>
                <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                  <Value>objectId</Value>
                  <Action>SkipThisValidationTechnicalProfile</Action>
                </Precondition>
              </Preconditions>
            </ValidationTechnicalProfile>

            <ValidationTechnicalProfile ReferenceId="AAD-MigrateUserUsingLogonEmail">
              <!--Don't run this validation technical profile if objectId is exists (existing acccount)-->
              <Preconditions>
                <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                  <Value>objectId</Value>
                  <Action>SkipThisValidationTechnicalProfile</Action>
                </Precondition>
              </Preconditions>
            </ValidationTechnicalProfile>

          </ValidationTechnicalProfiles>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

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

        <!--Demo: Checks if user exists in the migration table. If yes, validate the credentials and migrate the account -->
        <TechnicalProfile Id="REST-UserMigration-LocalAccount-SignIn">
          <DisplayName>Migrate user sign-in flow</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ServiceUrl">{Settings:LikvidoWebAppApiBaseUrl}/users/azure-ad-b2c/migrate</Item>
            <Item Key="AuthenticationType">None</Item>
            <Item Key="SendClaimsIn">Body</Item>
            <Item Key="AllowInsecureAuthInProduction">True</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="signInName" />
            <InputClaim ClaimTypeReferenceId="password" />
            <InputClaim ClaimTypeReferenceId="useInputPassword" DefaultValue="false" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="needToMigrate" />
            <OutputClaim ClaimTypeReferenceId="email" />
            <OutputClaim ClaimTypeReferenceId="newPassword" />
            <OutputClaim ClaimTypeReferenceId="displayName" />
            <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="firstName" />
            <OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="lastName" />
            <OutputClaim ClaimTypeReferenceId="extension_creditorId" PartnerClaimType="creditorId" />
            <OutputClaim ClaimTypeReferenceId="extension_likvidoUserId" PartnerClaimType="likvidoUserId" />
            <OutputClaim ClaimTypeReferenceId="extension_likvidoRole" PartnerClaimType="likvidoRole" />
            <OutputClaim ClaimTypeReferenceId="extension_title" PartnerClaimType="title" />
          </OutputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>

        <!--Demo: Checks if user exists in the migration table. If yes, raises an error -->
        <TechnicalProfile Id="REST-UserMigration-LocalAccount-SignUp">
          <DisplayName>Migrate user sign-in flow</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ServiceUrl">{Settings:LikvidoWebAppApiBaseUrl}/users/azure-ad-b2c/raise-error-if-exists</Item>
            <Item Key="AuthenticationType">None</Item>
            <Item Key="SendClaimsIn">Body</Item>
            <Item Key="AllowInsecureAuthInProduction">True</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInName" />
          </InputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>

        <!--Demo: Checks if user exists in Azure AD B2C or the migration table. If not, raises an error -->
        <TechnicalProfile Id="REST-UserMigration-LocalAccount-PasswordReset1">
          <DisplayName>Migrate user sign-in flow</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ServiceUrl">{Settings:LikvidoWebAppApiBaseUrl}/users/azure-ad-b2c/raise-error-if-not-exists</Item>
            <Item Key="AuthenticationType">None</Item>
            <Item Key="SendClaimsIn">Body</Item>
            <Item Key="AllowInsecureAuthInProduction">True</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInName" />
            <InputClaim ClaimTypeReferenceId="objectId" />
          </InputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>

        <TechnicalProfile Id="REST-UserMigration-LocalAccount-PasswordReset2">
          <DisplayName>Migrate user sign-in flow</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ServiceUrl">{Settings:LikvidoWebAppApiBaseUrl}/users/azure-ad-b2c/migrate</Item>
            <Item Key="AuthenticationType">None</Item>
            <Item Key="SendClaimsIn">Body</Item>
            <Item Key="AllowInsecureAuthInProduction">True</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInName" />
            <!-- <InputClaim ClaimTypeReferenceId="password" /> -->
            <InputClaim ClaimTypeReferenceId="useInputPassword" DefaultValue="true" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="needToMigrate" />
            <OutputClaim ClaimTypeReferenceId="email" />
            <!-- Don't return the new password <OutputClaim ClaimTypeReferenceId="newPassword" /> -->
            <OutputClaim ClaimTypeReferenceId="displayName" />
            <OutputClaim ClaimTypeReferenceId="givenName" />
            <OutputClaim ClaimTypeReferenceId="surName" />
          </OutputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

    <!-- Local account Sign-In claims provider -->
    <ClaimsProvider>
      <DisplayName>Local Account SignIn</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="login-NonInteractive">
          <DisplayName>Local Account SignIn</DisplayName>
          <Protocol Name="OpenIdConnect" />
          <Metadata>
            <Item Key="UserMessageIfClaimsPrincipalDoesNotExist">We can't seem to find your account</Item>
            <Item Key="UserMessageIfInvalidPassword">Your password is incorrect</Item>
            <Item Key="UserMessageIfOldPasswordUsed">Looks like you used an old password</Item>

            <Item Key="ProviderName">https://sts.windows.net/</Item>
            <Item Key="METADATA">https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration</Item>
            <Item Key="authorization_endpoint">https://login.microsoftonline.com/{tenant}/oauth2/token</Item>
            <Item Key="response_types">id_token</Item>
            <Item Key="response_mode">query</Item>
            <Item Key="scope">email openid</Item>
            <Item Key="grant_type">password</Item>

            <!-- Policy Engine Clients -->
            <Item Key="UsePolicyInRedirectUri">false</Item>
            <Item Key="HttpBinding">POST</Item>

            <Item Key="client_id">{Settings:ProxyIdentityExperienceFrameworkAppId}</Item>
            <Item Key="IdTokenAudience">{Settings:IdentityExperienceFramework}</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="username" Required="true" />
            <InputClaim ClaimTypeReferenceId="password" Required="true" />
            <InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" />
            <InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" />
            <InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" />

            <InputClaim ClaimTypeReferenceId="client_id" DefaultValue="{Settings:ProxyIdentityExperienceFrameworkAppId}" />
            <InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="{Settings:IdentityExperienceFramework}" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" />
            <OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid" />
            <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
            <OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
            <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
            <OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="upn" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />

            <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
            <OutputClaim ClaimTypeReferenceId="extension_creditorId" /> 
            <OutputClaim ClaimTypeReferenceId="extension_likvidoUserId" />  
            <OutputClaim ClaimTypeReferenceId="extension_likvidoRole" />    
            <OutputClaim ClaimTypeReferenceId="extension_title" />
          </OutputClaims>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

    <ClaimsProvider>
      <DisplayName>Azure Active Directory</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="AAD-MigrateUserUsingLogonEmail">
          <Metadata>
            <Item Key="Operation">Write</Item>
            <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
          </Metadata>
          <IncludeInSso>false</IncludeInSso>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
          </InputClaims>
          <PersistedClaims>
            <!-- Required claims -->
            <PersistedClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />
            <PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password"/>
            <PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
            <PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration,DisableStrongPassword" AlwaysUseDefaultValue="true"/>

            <!-- Optional claims. -->
            <PersistedClaim ClaimTypeReferenceId="givenName" />
            <PersistedClaim ClaimTypeReferenceId="surname" />
            <PersistedClaim ClaimTypeReferenceId="extension_creditorId" />  
            <PersistedClaim ClaimTypeReferenceId="extension_likvidoUserId" />   
            <PersistedClaim ClaimTypeReferenceId="extension_likvidoRole" /> 
            <PersistedClaim ClaimTypeReferenceId="extension_title" />
          </PersistedClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
            <OutputClaim ClaimTypeReferenceId="userPrincipalName" />

            <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
            <OutputClaim ClaimTypeReferenceId="extension_creditorId" /> 
            <OutputClaim ClaimTypeReferenceId="extension_likvidoUserId" />  
            <OutputClaim ClaimTypeReferenceId="extension_likvidoRole" />    
            <OutputClaim ClaimTypeReferenceId="extension_title" />
          </OutputClaims>
          <IncludeTechnicalProfile ReferenceId="AAD-Common" />
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

    <!-- Facebook claims provider -->
    <ClaimsProvider>
      <DisplayName>Facebook</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="Facebook-OAUTH">
          <Metadata>
            <!--Demo action required: Change to your Facebook App Id-->
            <Item Key="client_id">TODO</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>
  </ClaimsProviders>

  <!--<UserJourneys>
  </UserJourneys>-->

</TrustFrameworkPolicy>

上传此自定义配置文件工作正常,但当我也将这些声明添加到 SignUpOrSignIn.xml 文件时,我收到验证错误。这是我完整的 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="{Settings:Tenant}" PolicyId="B2C_1A_JITMigraion_signup_signin" PublicPolicyUri="http://{Settings:Tenant}/B2C_1A_JITMigraion_signup_signin">

  <BasePolicy>
    <TenantId>{Settings:Tenant}</TenantId>
    <PolicyId>B2C_1A_JITMigraion_TrustFrameworkExtensions</PolicyId>
  </BasePolicy>

  <RelyingParty>
    <DefaultUserJourney ReferenceId="SignUpOrSignIn" />

    <TechnicalProfile Id="PolicyProfile">
      <DisplayName>PolicyProfile</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration, DisableStrongPassword"/>
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="displayName" />
        <OutputClaim ClaimTypeReferenceId="givenName" />
        <OutputClaim ClaimTypeReferenceId="surname" />
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
        <OutputClaim ClaimTypeReferenceId="identityProvider" />
        <OutputClaim ClaimTypeReferenceId="needToMigrate" DefaultValue="false" />

        <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
        <OutputClaim ClaimTypeReferenceId="extension_creditorId" PartnerClaimType="creditorId" />   
        <OutputClaim ClaimTypeReferenceId="extension_likvidoUserId" PartnerClaimType="likvidoUserId" /> 
        <OutputClaim ClaimTypeReferenceId="extension_likvidoRole" PartnerClaimType="likvidoRole" /> 
        <OutputClaim ClaimTypeReferenceId="extension_title" PartnerClaimType="title" />
      </OutputClaims>
      <SubjectNamingInfo ClaimType="sub" />
    </TechnicalProfile>
  </RelyingParty>
</TrustFrameworkPolicy>

我在尝试上传此政策时收到这些错误消息:

Validation failed: 4 validation error(s) found in policy "B2C_1A_JITMIGRAION_SIGNUP_SIGNIN" of tenant "likvidostaging.onmicrosoft.com".

Claim type "extension_creditorId" is the output claim of the relying party's technical profile, but it is not an output claim in any of the steps of user journey "SignUpOrSignIn".

Claim type "extension_likvidoUserId" is the output claim of the relying party's technical profile, but it is not an output claim in any of the steps of user journey "SignUpOrSignIn".

Claim type "extension_likvidoRole" is the output claim of the relying party's technical profile, but it is not an output claim in any of the steps of user journey "SignUpOrSignIn".

Claim type "extension_title" is the output claim of the relying party's technical profile, but it is not an output claim in any of the steps of user journey "SignUpOrSignIn".

我不明白我在这里做错了什么,所以非常感谢您的帮助!

我现在知道如何让它工作了。显然,还需要将这些输出声明添加到 SelfAsserted-LocalAccountSignin-Email 技术配置文件中(不知道为什么)。

所以,我的结果 TrustedFrameworkExtensions.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="{Settings:Tenant}" PolicyId="B2C_1A_JITMigraion_TrustFrameworkExtensions" PublicPolicyUri="http://{Settings:Tenant}/B2C_1A_JITMigraion_TrustFrameworkExtensions">

  <BasePolicy>
    <TenantId>{Settings:Tenant}</TenantId>
    <PolicyId>B2C_1A_JITMigraion_TrustFrameworkBase</PolicyId>
  </BasePolicy>
  <BuildingBlocks>
    <ClaimsSchema>
      <!--Demo: This claim indicates whether the user need to migrate-->
      <ClaimType Id="needToMigrate">
        <DisplayName>needToMigrate</DisplayName>
        <DataType>string</DataType>
        <AdminHelpText>Indicates whether the user need to migrate</AdminHelpText>
        <UserHelpText>Indicates whether the user need to migrate</UserHelpText>
      </ClaimType>
      <ClaimType Id="useInputPassword">
        <DisplayName>useInputPassword</DisplayName>
        <DataType>boolean</DataType>
      </ClaimType>

      <ClaimType Id="extension_creditorId">
        <DisplayName>Creditor ID</DisplayName>
        <DataType>int</DataType>
        <AdminHelpText>The ID of the creditor this user belongs to</AdminHelpText>
        <UserHelpText>The ID of the creditor this user belongs to</UserHelpText>
      </ClaimType>
      <ClaimType Id="extension_likvidoUserId">
        <DisplayName>Likvido user ID</DisplayName>
        <DataType>string</DataType>
        <AdminHelpText>The ID of the user in the Likvido DB</AdminHelpText>
        <UserHelpText>The ID of the user in the Likvido DB</UserHelpText>
      </ClaimType>
      <ClaimType Id="extension_likvidoRole">
        <DisplayName>Likvido user role</DisplayName>
        <DataType>string</DataType>
        <AdminHelpText>The role of the user in Likvido</AdminHelpText>
        <UserHelpText>The role of the user in Likvido</UserHelpText>
      </ClaimType>
      <ClaimType Id="extension_title">
        <DisplayName>Likvido user title</DisplayName>
        <DataType>string</DataType>
        <AdminHelpText>The title of the user</AdminHelpText>
        <UserHelpText>The title of the user</UserHelpText>
      </ClaimType>
    </ClaimsSchema>
  </BuildingBlocks>

  <ClaimsProviders>
    <ClaimsProvider>
      <DisplayName>Azure Active Directory</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="AAD-Common">
          <Metadata>
            <!--Insert b2c-extensions-app application ID here, for example: 11111111-1111-1111-1111-111111111111-->  
            <Item Key="ClientId">{Settings:B2CExtensionsAppClientId}</Item>
            <!--Insert b2c-extensions-app application ObjectId here, for example: 22222222-2222-2222-2222-222222222222-->
            <Item Key="ApplicationObjectId">{Settings:B2CExtensionsAppObjectId}</Item>
          </Metadata>
        </TechnicalProfile>
      </TechnicalProfiles> 
    </ClaimsProvider>
    <!-- Local account Sign-Up claims provider -->
    <ClaimsProvider>
      <DisplayName>Local Account</DisplayName>
      <TechnicalProfiles>

        <!-- SIGN-IN -->
        <TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="needToMigrate" />
            <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
            <OutputClaim ClaimTypeReferenceId="extension_creditorId" /> 
            <OutputClaim ClaimTypeReferenceId="extension_likvidoUserId" />  
            <OutputClaim ClaimTypeReferenceId="extension_likvidoRole" />    
            <OutputClaim ClaimTypeReferenceId="extension_title" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <!--Demo: Add user migration validation technical profile before login-NonInteractive -->
            <ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-SignIn" ContinueOnError="false" />

            <!--Demo: Run this validation technical profile only if user doesn't need to migrate -->
            <ValidationTechnicalProfile ReferenceId="login-NonInteractive">
              <Preconditions>
                <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
                  <Value>needToMigrate</Value>
                  <Value>local</Value>
                  <Action>SkipThisValidationTechnicalProfile</Action>
                </Precondition>
              </Preconditions>
            </ValidationTechnicalProfile>

            <!--Demo: Run this validation technical profile only if user needs to migrate -->
            <ValidationTechnicalProfile ReferenceId="AAD-MigrateUserUsingLogonEmail">
              <Preconditions>
                <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
                  <Value>needToMigrate</Value>
                  <Value>local</Value>
                  <Action>SkipThisValidationTechnicalProfile</Action>
                </Precondition>
              </Preconditions>
            </ValidationTechnicalProfile>

          </ValidationTechnicalProfiles>
        </TechnicalProfile>

        <!-- SIGN-UP -->
        <TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
          <Metadata>
            <Item Key="EnforceEmailVerification">False</Item>
          </Metadata>
          <ValidationTechnicalProfiles>
            <!--Demo: Add user migration validation technical profile before AAD-UserWriteUsingLogonEmail -->
            <ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-SignUp" ContinueOnError="false" />
            <ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" ContinueOnError="false" />
          </ValidationTechnicalProfiles>
        </TechnicalProfile>

        <!-- PASSWORD RESET first page -->
        <TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
          <Metadata>
            <Item Key="EnforceEmailVerification">False</Item>
          </Metadata>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" ContinueOnError="true" />
            <ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-PasswordReset1" ContinueOnError="false" />
          </ValidationTechnicalProfiles>
        </TechnicalProfile>

        <!-- PASSWORD RESET second page -->
        <TechnicalProfile Id="LocalAccountWritePasswordUsingObjectId">
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="AAD-UserWritePasswordUsingObjectId">
              <!--Don't run this validation technical profile if objectId is not exists (migrated acccount)-->
              <Preconditions>
                <Precondition Type="ClaimsExist" ExecuteActionsIf="false">
                  <Value>objectId</Value>
                  <Action>SkipThisValidationTechnicalProfile</Action>
                </Precondition>
              </Preconditions>
            </ValidationTechnicalProfile>

            <ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-PasswordReset2">
              <!--Don't run this validation technical profile if objectId is exists (existing acccount)-->
              <Preconditions>
                <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                  <Value>objectId</Value>
                  <Action>SkipThisValidationTechnicalProfile</Action>
                </Precondition>
              </Preconditions>
            </ValidationTechnicalProfile>

            <ValidationTechnicalProfile ReferenceId="AAD-MigrateUserUsingLogonEmail">
              <!--Don't run this validation technical profile if objectId is exists (existing acccount)-->
              <Preconditions>
                <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                  <Value>objectId</Value>
                  <Action>SkipThisValidationTechnicalProfile</Action>
                </Precondition>
              </Preconditions>
            </ValidationTechnicalProfile>

          </ValidationTechnicalProfiles>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

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

        <!--Demo: Checks if user exists in the migration table. If yes, validate the credentials and migrate the account -->
        <TechnicalProfile Id="REST-UserMigration-LocalAccount-SignIn">
          <DisplayName>Migrate user sign-in flow</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ServiceUrl">{Settings:LikvidoWebAppApiBaseUrl}/users/azure-ad-b2c/migrate</Item>
            <Item Key="AuthenticationType">None</Item>
            <Item Key="SendClaimsIn">Body</Item>
            <Item Key="AllowInsecureAuthInProduction">True</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="signInName" />
            <InputClaim ClaimTypeReferenceId="password" />
            <InputClaim ClaimTypeReferenceId="useInputPassword" DefaultValue="false" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="needToMigrate" />
            <OutputClaim ClaimTypeReferenceId="email" />
            <OutputClaim ClaimTypeReferenceId="newPassword" />
            <OutputClaim ClaimTypeReferenceId="displayName" />
            <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="firstName" />
            <OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="lastName" />
            <OutputClaim ClaimTypeReferenceId="extension_creditorId" PartnerClaimType="creditorId" />
            <OutputClaim ClaimTypeReferenceId="extension_likvidoUserId" PartnerClaimType="likvidoUserId" />
            <OutputClaim ClaimTypeReferenceId="extension_likvidoRole" PartnerClaimType="likvidoRole" />
            <OutputClaim ClaimTypeReferenceId="extension_title" PartnerClaimType="title" />
          </OutputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>

        <!--Demo: Checks if user exists in the migration table. If yes, raises an error -->
        <TechnicalProfile Id="REST-UserMigration-LocalAccount-SignUp">
          <DisplayName>Migrate user sign-in flow</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ServiceUrl">{Settings:LikvidoWebAppApiBaseUrl}/users/azure-ad-b2c/raise-error-if-exists</Item>
            <Item Key="AuthenticationType">None</Item>
            <Item Key="SendClaimsIn">Body</Item>
            <Item Key="AllowInsecureAuthInProduction">True</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInName" />
          </InputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>

        <!--Demo: Checks if user exists in Azure AD B2C or the migration table. If not, raises an error -->
        <TechnicalProfile Id="REST-UserMigration-LocalAccount-PasswordReset1">
          <DisplayName>Migrate user sign-in flow</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ServiceUrl">{Settings:LikvidoWebAppApiBaseUrl}/users/azure-ad-b2c/raise-error-if-not-exists</Item>
            <Item Key="AuthenticationType">None</Item>
            <Item Key="SendClaimsIn">Body</Item>
            <Item Key="AllowInsecureAuthInProduction">True</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInName" />
            <InputClaim ClaimTypeReferenceId="objectId" />
          </InputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>

        <TechnicalProfile Id="REST-UserMigration-LocalAccount-PasswordReset2">
          <DisplayName>Migrate user sign-in flow</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ServiceUrl">{Settings:LikvidoWebAppApiBaseUrl}/users/azure-ad-b2c/migrate</Item>
            <Item Key="AuthenticationType">None</Item>
            <Item Key="SendClaimsIn">Body</Item>
            <Item Key="AllowInsecureAuthInProduction">True</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInName" />
            <!-- <InputClaim ClaimTypeReferenceId="password" /> -->
            <InputClaim ClaimTypeReferenceId="useInputPassword" DefaultValue="true" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="needToMigrate" />
            <OutputClaim ClaimTypeReferenceId="email" />
            <!-- Don't return the new password <OutputClaim ClaimTypeReferenceId="newPassword" /> -->
            <OutputClaim ClaimTypeReferenceId="displayName" />
            <OutputClaim ClaimTypeReferenceId="givenName" />
            <OutputClaim ClaimTypeReferenceId="surName" />
          </OutputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

    <!-- Local account Sign-In claims provider -->
    <ClaimsProvider>
      <DisplayName>Local Account SignIn</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="login-NonInteractive">
          <DisplayName>Local Account SignIn</DisplayName>
          <Protocol Name="OpenIdConnect" />
          <Metadata>
            <Item Key="UserMessageIfClaimsPrincipalDoesNotExist">We can't seem to find your account</Item>
            <Item Key="UserMessageIfInvalidPassword">Your password is incorrect</Item>
            <Item Key="UserMessageIfOldPasswordUsed">Looks like you used an old password</Item>

            <Item Key="ProviderName">https://sts.windows.net/</Item>
            <Item Key="METADATA">https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration</Item>
            <Item Key="authorization_endpoint">https://login.microsoftonline.com/{tenant}/oauth2/token</Item>
            <Item Key="response_types">id_token</Item>
            <Item Key="response_mode">query</Item>
            <Item Key="scope">email openid</Item>
            <Item Key="grant_type">password</Item>

            <!-- Policy Engine Clients -->
            <Item Key="UsePolicyInRedirectUri">false</Item>
            <Item Key="HttpBinding">POST</Item>

            <Item Key="client_id">{Settings:ProxyIdentityExperienceFrameworkAppId}</Item>
            <Item Key="IdTokenAudience">{Settings:IdentityExperienceFramework}</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="username" Required="true" />
            <InputClaim ClaimTypeReferenceId="password" Required="true" />
            <InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" />
            <InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" />
            <InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" />

            <InputClaim ClaimTypeReferenceId="client_id" DefaultValue="{Settings:ProxyIdentityExperienceFrameworkAppId}" />
            <InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="{Settings:IdentityExperienceFramework}" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" />
            <OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid" />
            <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
            <OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
            <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
            <OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="upn" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />

            <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
            <OutputClaim ClaimTypeReferenceId="extension_creditorId" /> 
            <OutputClaim ClaimTypeReferenceId="extension_likvidoUserId" />  
            <OutputClaim ClaimTypeReferenceId="extension_likvidoRole" />    
            <OutputClaim ClaimTypeReferenceId="extension_title" />
          </OutputClaims>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

    <ClaimsProvider>
      <DisplayName>Azure Active Directory</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="AAD-MigrateUserUsingLogonEmail">
          <Metadata>
            <Item Key="Operation">Write</Item>
            <Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
          </Metadata>
          <IncludeInSso>false</IncludeInSso>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
          </InputClaims>
          <PersistedClaims>
            <!-- Required claims -->
            <PersistedClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" />
            <PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password"/>
            <PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
            <PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration,DisableStrongPassword" AlwaysUseDefaultValue="true"/>

            <!-- Optional claims. -->
            <PersistedClaim ClaimTypeReferenceId="givenName" />
            <PersistedClaim ClaimTypeReferenceId="surname" />
            <PersistedClaim ClaimTypeReferenceId="extension_creditorId" />  
            <PersistedClaim ClaimTypeReferenceId="extension_likvidoUserId" />   
            <PersistedClaim ClaimTypeReferenceId="extension_likvidoRole" /> 
            <PersistedClaim ClaimTypeReferenceId="extension_title" />
          </PersistedClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
            <OutputClaim ClaimTypeReferenceId="userPrincipalName" />

            <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
            <OutputClaim ClaimTypeReferenceId="extension_creditorId" /> 
            <OutputClaim ClaimTypeReferenceId="extension_likvidoUserId" />  
            <OutputClaim ClaimTypeReferenceId="extension_likvidoRole" />    
            <OutputClaim ClaimTypeReferenceId="extension_title" />
          </OutputClaims>
          <IncludeTechnicalProfile ReferenceId="AAD-Common" />
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

    <!-- Facebook claims provider -->
    <ClaimsProvider>
      <DisplayName>Facebook</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="Facebook-OAUTH">
          <Metadata>
            <!--Demo action required: Change to your Facebook App Id-->
            <Item Key="client_id">TODO</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>
  </ClaimsProviders>

  <!--<UserJourneys>
  </UserJourneys>-->

</TrustFrameworkPolicy>

The scope of the output claims of a validation technical profile is limited to the self-asserted technical profile that invokes the validation technical profile, and its validation technical profiles. If you want to use the output claims in the next orchestration step, add the output claims to the self-asserted technical profile that invokes the validation technical profile.

https://docs.microsoft.com/en-us/azure/active-directory-b2c/validation-technical-profile