You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure AD B2C自定义策略限制每日密码重置次数报错求助

Azure AD B2C自定义策略:密码重置每日次数限制配置问题

我有一个带密码重置功能的Azure AD B2C自定义策略,现在要将密码重置限制为每日5次,配置后出现错误,以下是相关配置和错误信息:

Claims Schema

<ClaimType Id="extension_MaxPasswordResets">
  <DisplayName>Max Password Resets</DisplayName>
  <DataType>long</DataType>
  <AdminHelpText>Stores the number of password resets for the user.</AdminHelpText>
  <UserHelpText>Stores the number of password resets for the user.</UserHelpText>
</ClaimType>
<ClaimType Id="allowPasswordReset">
  <DisplayName>Allow Password Reset</DisplayName>
  <DataType>boolean</DataType>
  <UserHelpText>Indicates whether password reset is allowed.</UserHelpText>
</ClaimType>

ClaimsTransformations

<ClaimsTransformations>
  <!-- Other transformations -->
  <!-- Transformation to check if the password reset count is less than or equal to 5 -->
  <ClaimsTransformation Id="AssertBooleanClaimIsLessOrEqualToValue" TransformationMethod="AssertBooleanClaimIsEqualToValue">
    <InputClaims>
      <InputClaim ClaimTypeReferenceId="extension_MaxPasswordResets" TransformationClaimType="inputClaim" />
    </InputClaims>
    <InputParameters>
      <InputParameter Id="valueToCompareTo" DataType="long" Value="5" />
      <InputParameter Id="operator" DataType="string" Value="lessOrEquals" />
    </InputParameters>
    <OutputClaims>
      <OutputClaim ClaimTypeReferenceId="allowPasswordReset" TransformationClaimType="outputClaim" />
    </OutputClaims>
  </ClaimsTransformation>
</ClaimsTransformations>

TechnicalProfile

<TechnicalProfile Id="CheckPasswordResetCount">
  <DisplayName>Check Password Reset Count</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <Metadata>
    <Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
  </Metadata>
  <InputClaims>
    <!-- Reference the claim that stores the password reset count -->
    <InputClaim ClaimTypeReferenceId="extension_MaxPasswordResets" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="allowPasswordReset" DefaultValue="false" />
  </OutputClaims>
  <OutputClaimsTransformations>
    <!-- Check if the password reset count exceeds 5 -->
    <OutputClaimsTransformation ReferenceId="AssertBooleanClaimIsLessOrEqualToValue" />
  </OutputClaimsTransformations>
  <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>

密码重置子旅程

<SubJourney Id="PasswordReset" Type="Call">
  <OrchestrationSteps>
    <!-- Step to check the password reset count before proceeding -->
    <OrchestrationStep Order="1" Type="ClaimsExchange">
      <Preconditions>
        <!-- Check if the user is trying to reset the password -->
        <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
          <Value>passwordreset</Value>
          <Value>true</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <!-- <ValidationTechnicalProfiles>
        <ValidationTechnicalProfile ReferenceId="CheckPasswordResetCount" />
      </ValidationTechnicalProfiles> -->
      <ClaimsExchanges>
        <!-- Perform a claims exchange with the custom validation technical profile -->
        <ClaimsExchange Id="MyCustomValidationExchange" TechnicalProfileReferenceId="CheckPasswordResetCount" />
      </ClaimsExchanges>
    </OrchestrationStep>
    <!-- Validate user's email address. Run this step only when user resets the password-->
    <OrchestrationStep Order="2" Type="ClaimsExchange">
      <Preconditions>
        <!-- Check if the user is trying to reset the password -->
        <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
          <Value>passwordreset</Value>
          <Value>true</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="PasswordResetUsingEmailAddressExchange" TechnicalProfileReferenceId="LocalAccountDiscoveryUsingEmailAddress-AcctExists" />
      </ClaimsExchanges>
    </OrchestrationStep>
    <!-- Collect and persist a new password. Run this step only when user resets the password-->
    <OrchestrationStep Order="3" Type="ClaimsExchange">
      <Preconditions>
        <!-- Check if the user is trying to reset the password -->
        <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
          <Value>passwordreset</Value>
          <Value>true</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="NewCredentials" TechnicalProfileReferenceId="LocalAccountWritePasswordUsingObjectId" />
      </ClaimsExchanges>
    </OrchestrationStep>
  </OrchestrationSteps>
</SubJourney>

错误信息

The InputClaims mismatched in ClaimsTransformation with id "AssertBooleanClaimIsLessOrEqualToValue" with TransformationMethod "AssertBooleanClaimIsEqualToValue". The following InputClaims were declared in the Policy but were not expected by the TransformMethod: [Long]inputClaim. The following InputClaims were expected by the TransformMethod but were not declared in the Policy: [Boolean]inputClaim.


解决方案

1. 修正ClaimsTransformation方法类型

错误根源是使用了AssertBooleanClaimIsEqualToValue方法,该方法仅适用于布尔类型断言,但传入的是long类型计数。需改用**AssertNumericClaimIsLessThanOrEqualToValue**方法,专门处理数值类型比较:

<ClaimsTransformations>
  <!-- 替换原有的断言转换 -->
  <ClaimsTransformation Id="AssertPasswordResetCountUnderLimit" TransformationMethod="AssertNumericClaimIsLessThanOrEqualToValue">
    <InputClaims>
      <InputClaim ClaimTypeReferenceId="extension_MaxPasswordResets" TransformationClaimType="inputClaim" />
    </InputClaims>
    <InputParameters>
      <InputParameter Id="valueToCompareTo" DataType="long" Value="5" />
      <InputParameter Id="throwException" DataType="boolean" Value="true" />
    </InputParameters>
  </ClaimsTransformation>
</ClaimsTransformations>

2. 更新CheckPasswordResetCount技术配置

调整技术配置中的输出转换引用,该断言方法会在计数超出限制时直接抛出异常中断流程,无需输出allowPasswordReset:

<TechnicalProfile Id="CheckPasswordResetCount">
  <DisplayName>Check Password Reset Count</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <Metadata>
    <Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
  </Metadata>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="extension_MaxPasswordResets" />
  </InputClaims>
  <OutputClaimsTransformations>
    <OutputClaimsTransformation ReferenceId="AssertPasswordResetCountUnderLimit" />
  </OutputClaimsTransformations>
  <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>

3. 补充每日计数重置逻辑(关键)

当前配置仅存储总重置次数,需添加日期跟踪和计数重置逻辑实现每日限制:

新增Claims Schema

<ClaimType Id="extension_LastPasswordResetDate">
  <DisplayName>Last Password Reset Date</DisplayName>
  <DataType>date</DataType>
  <AdminHelpText>Stores the date of the last password reset.</AdminHelpText>
</ClaimType>
<ClaimType Id="currentDate">
  <DisplayName>Current Date</DisplayName>
  <DataType>date</DataType>
</ClaimType>

新增ClaimsTransformations

<!-- 获取当前日期 -->
<ClaimsTransformation Id="GetCurrentDate" TransformationMethod="GetCurrentDate">
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="currentDate" TransformationClaimType="currentDate" />
  </OutputClaims>
</ClaimsTransformation>

<!-- 重置计数到1(日期变化时) -->
<ClaimsTransformation Id="ResetPasswordResetCount" TransformationMethod="CreateStringClaim">
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="extension_MaxPasswordResets" TransformationClaimType="createdClaim" Value="1" />
  </OutputClaims>
</ClaimsTransformation>

<!-- 计数加1 -->
<ClaimsTransformation Id="IncrementPasswordResetCount" TransformationMethod="IncrementNumericClaim">
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="extension_MaxPasswordResets" TransformationClaimType="inputClaim" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="extension_MaxPasswordResets" TransformationClaimType="outputClaim" />
  </OutputClaims>
</ClaimsTransformation>

<!-- 复制当前日期到最后重置日期 -->
<ClaimsTransformation Id="CopyCurrentDateToLastResetDate" TransformationMethod="CopyClaim">
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="currentDate" TransformationClaimType="inputClaim" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="extension_LastPasswordResetDate" TransformationClaimType="outputClaim" />
  </OutputClaims>
</ClaimsTransformation>

创建计数更新技术配置

<TechnicalProfile Id="UpdatePasswordResetCount">
  <DisplayName>Update Password Reset Count</DisplayName>
  <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  <Metadata>
    <Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
  </Metadata>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="extension_LastPasswordResetDate" />
    <InputClaim ClaimTypeReferenceId="extension_MaxPasswordResets" DefaultValue="0" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="extension_MaxPasswordResets" />
    <OutputClaim ClaimTypeReferenceId="extension_LastPasswordResetDate" />
  </OutputClaims>
  <OutputClaimsTransformations>
    <OutputClaimsTransformation ReferenceId="GetCurrentDate" />
    <!-- 日期不同则重置计数 -->
    <OutputClaimsTransformation ReferenceId="ResetPasswordResetCount">
      <Preconditions>
        <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
          <Value>extension_LastPasswordResetDate</Value>
          <Value>currentDate</Value>
          <Action>SkipThisClaimsTransformation</Action>
        </Precondition>
      </Preconditions>
    </OutputClaimsTransformation>
    <!-- 日期相同则计数加1 -->
    <OutputClaimsTransformation ReferenceId="IncrementPasswordResetCount">
      <Preconditions>
        <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
          <Value>extension_LastPasswordResetDate</Value>
          <Value>currentDate</Value>
          <Action>SkipThisClaimsTransformation</Action>
        </Precondition>
      </Preconditions>
    </OutputClaimsTransformation>
    <!-- 更新最后重置日期 -->
    <OutputClaimsTransformation ReferenceId="CopyCurrentDateToLastResetDate" />
  </OutputClaimsTransformations>
  <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>

更新子旅程添加计数更新步骤

在密码重置成功后添加计数更新和持久化步骤:

<SubJourney Id="PasswordReset" Type="Call">
  <OrchestrationSteps>
    <!-- 原步骤1:检查重置计数 -->
    <OrchestrationStep Order="1" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
          <Value>passwordreset</Value>
          <Value>true</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="CheckResetCount" TechnicalProfileReferenceId="CheckPasswordResetCount" />
      </ClaimsExchanges>
    </OrchestrationStep>
    <!-- 原步骤2:验证邮箱 -->
    <OrchestrationStep Order="2" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
          <Value>passwordreset</Value>
          <Value>true</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="PasswordResetUsingEmailAddressExchange" TechnicalProfileReferenceId="LocalAccountDiscoveryUsingEmailAddress-AcctExists" />
      </ClaimsExchanges>
    </OrchestrationStep>
    <!-- 原步骤3:重置密码 -->
    <OrchestrationStep Order="3" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
          <Value>passwordreset</Value>
          <Value>true</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="NewCredentials" TechnicalProfileReferenceId="LocalAccountWritePasswordUsingObjectId" />
      </ClaimsExchanges>
    </OrchestrationStep>
    <!-- 新增步骤4:更新重置计数和日期 -->
    <OrchestrationStep Order="4" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
          <Value>passwordreset</Value>
          <Value>true</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="UpdateResetCount" TechnicalProfileReferenceId="UpdatePasswordResetCount" />
      </ClaimsExchanges>
    </OrchestrationStep>
    <!-- 新增步骤5:持久化计数和日期到用户属性 -->
    <OrchestrationStep Order="5" Type="ClaimsExchange">
      <Preconditions>
        <Precondition Type="ClaimEquals" ExecuteActionsIf="false">
          <Value>passwordreset</Value>
          <Value>true</Value>
          <Action>SkipThisOrchestrationStep</Action>
        </Precondition>
      </Preconditions>
      <ClaimsExchanges>
        <ClaimsExchange Id="PersistResetCount" TechnicalProfileReferenceId="AAD-UserWriteProfileUsingObjectId" />
      </ClaimsExchanges>
    </OrchestrationStep>
  </OrchestrationSteps>
</SubJourney>

4. 配置用户属性

确保extension_MaxPasswordResets和extension_LastPasswordResetDate两个自定义属性已在Azure AD B2C租户中创建,并在策略的AAD技术配置中声明为可读写。


内容的提问来源于stack exchange,提问作者Dhanil Dinesan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 02:23:10