尽管已经同意,但在登录时会弹出服务条款

Terms of Service pops up on Sign-In although already agreed

我正在使用 Single-Page Application built on MSAL.js with Azure AD B2C together with the A B2C IEF Custom Policy - Sign Up and Sign In with 'Terms of Use' prompt 和自定义 RestAPI 配置文件来丰富输出声明。

一切似乎都很好,直到我按下应用程序的“呼叫 API”按钮,这会提示“我同意服务条款”弹出窗口:

这不应该发生,因为最新的服务条款已在注册时达成一致。如果我注销并再次登录,也会发生同样的情况。因此,以某种方式获取访问令牌会提示相同的弹出窗口。

我认为这个提示应该只在登录时显示(即在获取 ID 令牌时),所以我的配置有些不对。

顺便说一下,id 令牌对我来说很好:

我该如何解决这个问题?


这是我正在使用的自定义策略:

<?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="tenant.onmicrosoft.com" PolicyId="B2C_1A_TOU_SUSI" PublicPolicyUri="http://tenant.onmicrosoft.com/B2C_1A_TOU_SUSI">

  <BasePolicy>
    <TenantId>tenant.onmicrosoft.com</TenantId>
    <PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
  </BasePolicy>
  <BuildingBlocks>
    <ClaimsSchema>
      <ClaimType Id="extension_termsOfUseConsentChoice">
        <DisplayName></DisplayName>
        <DataType>string</DataType>
        <UserInputType>CheckboxMultiSelect</UserInputType>
        <Restriction>
          <Enumeration Text=" I agree to the Terms Of Service" Value="AgreeToTermsOfUseConsentYes" SelectByDefault="false" />
        </Restriction>
      </ClaimType>
      <ClaimType Id="currentTime">
        <DisplayName>Current Time</DisplayName>
        <DataType>dateTime</DataType>
        <AdminHelpText>Current date time in UTC.</AdminHelpText>
        <UserHelpText>Current date time in UTC.</UserHelpText>
      </ClaimType>
      <ClaimType Id="extension_termsOfUseConsentDateTime">
        <DisplayName>Terms of Use Consent Date Time</DisplayName>
        <DataType>dateTime</DataType>
        <AdminHelpText>Terms of Use Consent date time in UTC.</AdminHelpText>
        <UserHelpText>Terms of Use Consent date time in UTC.</UserHelpText>
      </ClaimType>
      <ClaimType Id="termsOfUseConsentRequired">
        <DisplayName>Terms of Use Consent Required</DisplayName>
        <DataType>boolean</DataType>
        <AdminHelpText>Boolean that specifies if Terms of Use Consent is required or not.</AdminHelpText>
        <UserHelpText>Boolean that specifies if Terms of Use Consent is required or not</UserHelpText>
      </ClaimType>
      <ClaimType Id="extension_termsOfUseConsentVersion">
        <DisplayName>Terms of Use Consent Version</DisplayName>
        <DataType>string</DataType>
        <AdminHelpText>Terms of Use Consent Version.</AdminHelpText>
        <UserHelpText>Terms of Use Consent Version.</UserHelpText>
      </ClaimType>
    <ClaimType Id="groupIds">
        <DisplayName>Your Group Ids</DisplayName>
        <DataType>stringCollection</DataType>
      </ClaimType>
    </ClaimsSchema>
    <ClaimsTransformations>
      <ClaimsTransformation Id="GetCurrentDateTime" TransformationMethod="GetCurrentDateTime">
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="currentTime" TransformationClaimType="currentDateTime" />
        </OutputClaims>
      </ClaimsTransformation>

      <ClaimsTransformation Id="IsTermsOfUseConsentRequiredForDateTime" TransformationMethod="IsTermsOfUseConsentRequired">
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="extension_termsOfUseConsentDateTime" TransformationClaimType="termsOfUseConsentDateTime" />
        </InputClaims>
        <InputParameters>
          <InputParameter Id="termsOfUseTextUpdateDateTime" DataType="dateTime" Value="2020-01-30T23:03:45" />
        </InputParameters>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="termsOfUseConsentRequired" TransformationClaimType="result" />
        </OutputClaims>
      </ClaimsTransformation>

      <ClaimsTransformation Id="GetNewUserAgreeToTermsOfUseConsentVersion" TransformationMethod="CreateStringClaim">
        <InputParameters>
          <InputParameter Id="value" DataType="string" Value="V1"/>
        </InputParameters>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="extension_termsOfUseConsentVersion" TransformationClaimType="createdClaim" />
        </OutputClaims>
      </ClaimsTransformation>

    <!-- Not used here, but this OR IsTermsOfUseConsentRequiredForDateTime check can be used -->
      <ClaimsTransformation Id="IsTermsOfUseConsentRequiredForVersion" TransformationMethod="CompareClaimToValue">
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="extension_termsOfUseConsentVersion" TransformationClaimType="inputClaim1" />
        </InputClaims>
        <InputParameters>
          <InputParameter Id="compareTo" DataType="string" Value="V2" />
          <InputParameter Id="operator" DataType="string" Value="not equal" />
          <InputParameter Id="ignoreCase" DataType="string" Value="true" />
        </InputParameters>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="termsOfUseConsentRequired" TransformationClaimType="outputClaim" />
        </OutputClaims>
      </ClaimsTransformation>
    </ClaimsTransformations>
  </BuildingBlocks>

  <ClaimsProviders>
    <ClaimsProvider>
    <!-- Page that prompts for a new TOU on sign in if the users TOU is out of date-->
      <DisplayName>Self Asserted</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="SelfAsserted-Input-ToU-SignIn">
          <DisplayName>Self Asserted ToU</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
            <Item Key="AllowGenerationOfClaimsWithNullValues">true</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
          </CryptographicKeys>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="objectId" />
            <InputClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" DefaultValue="AgreeToTermsOfUseConsentNo" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" Required="true" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="Update-TOU-Status" />
          </ValidationTechnicalProfiles>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>

    <ClaimsProvider>
      <DisplayName>Local Account</DisplayName>
      <TechnicalProfiles>

        <TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
          <DisplayName>Local Account Signin</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="SignUpTarget">SignUpWithLogonEmailExchange</Item>
            <Item Key="setting.operatingMode">Email</Item>
            <Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
          </Metadata>
          <IncludeInSso>false</IncludeInSso>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="signInName" />
            <InputClaim ClaimTypeReferenceId="currentTime" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
            <OutputClaim ClaimTypeReferenceId="password" Required="true" />
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" />
            <OutputClaim ClaimTypeReferenceId="termsOfUseConsentRequired"/>
            <OutputClaim ClaimTypeReferenceId="extension_termsOfUseConsentDateTime" />
            <OutputClaim ClaimTypeReferenceId="groupIds" DefaultValue="[]" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="GetCurrentDateTime" />
          </OutputClaimsTransformations>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
            <ValidationTechnicalProfile ReferenceId="Check-TOU-Status" />
            <ValidationTechnicalProfile ReferenceId="REST-GetProfile" />
          </ValidationTechnicalProfiles>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
        </TechnicalProfile>
        <!-- read the last time the user consented -->
        <TechnicalProfile Id="Check-TOU-Status">
          <Metadata>
            <Item Key="Operation">Read</Item>
            <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
          </Metadata>
          <IncludeInSso>false</IncludeInSso>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="objectId" Required="true" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="extension_termsOfUseConsentDateTime" DefaultValue="2017-10-01T15:00:00.0000000Z" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="IsTermsOfUseConsentRequiredForDateTime" />
          </OutputClaimsTransformations>
          <IncludeTechnicalProfile ReferenceId="AAD-Common" />
        </TechnicalProfile>

        <!-- write the current time to the consent attribute if the user reconsents to TOU on sign in -->
        <TechnicalProfile Id="Update-TOU-Status">
          <Metadata>
            <Item Key="Operation">Write</Item>
            <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
          </Metadata>
          <IncludeInSso>false</IncludeInSso>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="objectId" Required="true" />
          </InputClaims>
          <PersistedClaims>
            <PersistedClaim ClaimTypeReferenceId="objectId" />
            <PersistedClaim ClaimTypeReferenceId="currentTime" PartnerClaimType="extension_termsOfUseConsentDateTime" />
          </PersistedClaims>
          <IncludeTechnicalProfile ReferenceId="AAD-Common" />
        </TechnicalProfile>

        <!-- sign up page with TOU checkbox-->
        <TechnicalProfile Id="LocalAccountSignUpWithLogonEmailCustom">
          <DisplayName>Email signup</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
            <Item Key="language.button_continue">Create</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
          </CryptographicKeys>
          <InputClaimsTransformations>
            <InputClaimsTransformation ReferenceId="GetCurrentDateTime" />
          </InputClaimsTransformations>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" DefaultValue="AgreeToTermsOfUseConsentNo" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Email" Required="true" />
            <OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
            <OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
            <OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" />
            <OutputClaim ClaimTypeReferenceId="newUser" />

            <!-- Optional claims, to be collected from the user -->
            <!-- <OutputClaim ClaimTypeReferenceId="displayName" />
            <OutputClaim ClaimTypeReferenceId="givenName" />
            <OutputClaim ClaimTypeReferenceId="surName" /> -->
            <OutputClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" Required="true" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
          </ValidationTechnicalProfiles>
        </TechnicalProfile>

        <!-- During sign up, write the current time of consent, and version -->
        <TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
          <PersistedClaims>
            <PersistedClaim ClaimTypeReferenceId="currentTime" PartnerClaimType="extension_termsOfUseConsentDateTime"/>
            <PersistedClaim ClaimTypeReferenceId="extension_termsOfUseConsentChoice" />
            <PersistedClaim ClaimTypeReferenceId="extension_termsOfUseConsentVersion" DefaultValue="V1" />
          </PersistedClaims>
        </TechnicalProfile>

        <TechnicalProfile Id="REST-GetProfile">
          <DisplayName>Get user extended profile via a REST API call</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://<myserveraddress>/claims/GetGroupIds</Item>
            <Item Key="SendClaimsIn">Body</Item>
            <Item Key="AuthenticationType">Basic</Item>
            <Item Key="AllowInsecureAuthInProduction">false</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_RestApiUsername" />
            <Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_RestApiPassword" />
          </CryptographicKeys>
          <OutputClaims>
            <!-- Claims parsed from your REST API -->
            <OutputClaim ClaimTypeReferenceId="groupIds" />
          </OutputClaims>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>

        <TechnicalProfile Id="AAD-Common">
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="ApplicationObjectId"><MyApplicationObjectId></Item>
            <Item Key="ClientId"><MyClientId></Item>
          </Metadata>
        </TechnicalProfile>

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

  <UserJourneys>
    <UserJourney Id="B2CSignUpOrSignInWithPasswordToU" NonInteractive="false">
      <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
          <ClaimsProviderSelections>
            <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
          </ClaimsProviderSelections>
          <ClaimsExchanges>
            <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
          </ClaimsExchanges>
        </OrchestrationStep>

        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>objectId</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="LocalAccountSignUp" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmailCustom" />
          </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="3" Type="ClaimsExchange">
          <Preconditions>
            <!-- Add condition to not execute this step for sign up scenario based on newUser claim -->
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>newUser</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
          </ClaimsExchanges>
        </OrchestrationStep>

        <!-- Display Terms of Use consent page for any SignIn scenario based on termsOfUseConsentRequired claim -->
        <OrchestrationStep Order="4" Type="ClaimsExchange">
          <Preconditions>
            <!-- Add condition to not execute this step for sign up scenario based on newUser claim -->
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>newUser</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
              <Value>termsOfUseConsentRequired</Value>
              <Value>True</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="ShowToUConsentPageForNewUser" TechnicalProfileReferenceId="SelfAsserted-Input-ToU-SignIn" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="5" Type="ClaimsExchange">
        <ClaimsExchanges>
          <ClaimsExchange Id="RESTGetProfile" TechnicalProfileReferenceId="REST-GetProfile" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="6" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
      </OrchestrationSteps>
      <ClientDefinition ReferenceId="DefaultWeb" />
    </UserJourney>
  </UserJourneys>

  <RelyingParty>
    <DefaultUserJourney ReferenceId="B2CSignUpOrSignInWithPasswordToU" />
    <TechnicalProfile Id="PolicyProfile">
      <DisplayName>PolicyProfile</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="newUser" />
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
        <OutputClaim ClaimTypeReferenceId="extension_termsOfUseConsentDateTime" />
        <OutputClaim ClaimTypeReferenceId="currentTime" />
        <OutputClaim ClaimTypeReferenceId="email" />
        <OutputClaim ClaimTypeReferenceId="groupIds" DefaultValue="[]" />
        <OutputClaim ClaimTypeReferenceId="termsOfUseConsentRequired" />
        
      </OutputClaims>
      <SubjectNamingInfo ClaimType="sub" />
    </TechnicalProfile>
  </RelyingParty>

</TrustFrameworkPolicy>

你能加吗

        <TechnicalProfile Id="SM-AAD">
          <PersistedClaims>
            <PersistedClaim ClaimTypeReferenceId="termsOfUseConsentRequired" />
          </PersistedClaims>
        </TechnicalProfile>

这是因为当 运行 带有 prompt=none 的保单时,此termsOfUseConsentRequired 索赔未被评估(SSO/silent SPA 内的令牌调用)。