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

