Azure AD B2C自定义策略登录旅程MFA功能定制需求问询
一、核心流程改造:凭证校验后添加邮箱TOTP MFA
基于现有邮箱/ID密码登录流程,需在用户完成凭证校验后插入邮箱TOTP发送与验证环节,具体实现步骤如下:
添加TOTP技术配置
在自定义策略的<ClaimsProviders>节点下,新增TOTP发送与验证的声明提供方,配置邮箱发送服务(可对接Azure通信服务或自定义SMTP):<ClaimsProvider> <DisplayName>Email TOTP</DisplayName> <TechnicalProfiles> <!-- 发送TOTP到用户注册邮箱 --> <TechnicalProfile Id="Email-SendTOTP"> <DisplayName>Send TOTP to Email</DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.EmailProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <Metadata> <Item Key="SmtpServer">smtp.yourdomain.com</Item> <Item Key="SmtpPort">587</Item> <Item Key="Username">smtp-account@yourdomain.com</Item> <Item Key="Password">smtp-password</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="email" PartnerClaimType="to" /> <InputClaim ClaimTypeReferenceId="totpCode" PartnerClaimType="subject" /> </InputClaims> </TechnicalProfile> <!-- 验证用户输入的TOTP --> <TechnicalProfile Id="Email-VerifyTOTP"> <DisplayName>Verify TOTP</DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.TotpProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <Metadata> <Item Key="ValidationTimeInMinutes">10</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="totpCode" PartnerClaimType="otp" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="totpVerified" DefaultValue="true" /> </OutputClaims> </TechnicalProfile> </TechnicalProfiles> </ClaimsProvider>修改用户旅程流程
在现有登录用户旅程的OrchestrationSteps中,将TOTP发送与验证步骤插入到凭证校验步骤之后:<!-- 步骤N:凭证校验通过后,触发TOTP发送 --> <OrchestrationStep Order="N" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="SendTOTP" TechnicalProfileReferenceId="Email-SendTOTP" /> </ClaimsExchanges> </OrchestrationStep> <!-- 步骤N+1:显示TOTP验证界面,收集用户输入并校验 --> <OrchestrationStep Order="N+1" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="VerifyTOTP" TechnicalProfileReferenceId="Email-VerifyTOTP" /> </ClaimsExchanges> </OrchestrationStep>定制TOTP验证界面
在ContentDefinitions中配置TOTP验证页面,添加“30天内记住我”复选框:<ContentDefinition Id="api.selfasserted.verifytotp"> <LoadUri>~/tenant/templates/AzureBlue/selfAsserted.cshtml</LoadUri> <RecoveryUri>~/common/default_page_error.html</RecoveryUri> <DataUri>urn:com:microsoft:aad:b2c:elements:selfasserted:1.1.0</DataUri> <Metadata> <Item Key="DisplayName">Verify Email Code</Item> </Metadata> <LocalizedResourcesReferences MergeBehavior="Prepend"> <LocalizedResourcesReference Language="en" LocalizedResourcesReferenceId="api.selfasserted.en" /> </LocalizedResourcesReferences> </ContentDefinition>
二、实现“30天记住我跳过MFA”规则
利用Azure AD B2C的持久化会话和自定义声明,实现MFA跳过逻辑:
添加自定义声明
在<BuildingBlocks><ClaimsSchema>中新增用于标记“记住我”和存储上次MFA时间的声明:<ClaimType Id="rememberMe"> <DisplayName>Remember me for 30 days</DisplayName> <DataType>boolean</DataType> <UserInputType>Checkbox</UserInputType> </ClaimType> <ClaimType Id="lastMfaDate"> <DisplayName>Last MFA Verification Date</DisplayName> <DataType>dateTime</DataType> </ClaimType>持久化MFA验证记录
修改Email-VerifyTOTP技术配置,当用户勾选“记住我”时,将当前时间持久化到浏览器会话:<OutputClaims> <OutputClaim ClaimTypeReferenceId="totpVerified" DefaultValue="true" /> <OutputClaim ClaimTypeReferenceId="lastMfaDate" PartnerClaimType="persistentLastMfaDate" DefaultValue="{Context:DateTimeNow}" AlwaysUseDefaultValue="true" /> </OutputClaims> <PersistedClaims> <PersistedClaim ClaimTypeReferenceId="lastMfaDate" Condition="#{rememberMe} == true" /> </PersistedClaims>添加MFA跳过判断逻辑
在用户旅程起始处添加步骤,读取持久化的lastMfaDate并计算时间差,若小于30天则标记跳过MFA:<OrchestrationStep Order="1" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="CheckMfaSkipCondition" TechnicalProfileReferenceId="CheckMfaSkipCondition" /> </ClaimsExchanges> </OrchestrationStep> <!-- 定义判断技术配置 --> <TechnicalProfile Id="CheckMfaSkipCondition"> <DisplayName>Check if MFA can be skipped</DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <OutputClaims> <OutputClaim ClaimTypeReferenceId="skipMfa" DefaultValue="false" /> </OutputClaims> <OutputClaimsTransformations> <OutputClaimsTransformation ReferenceId="CalculateDaysSinceLastMfa" /> <OutputClaimsTransformation ReferenceId="SetSkipMfaIfWithin30Days" /> </OutputClaimsTransformations> </TechnicalProfile> <!-- 声明转换:计算距离上次MFA的天数 --> <ClaimsTransformation Id="CalculateDaysSinceLastMfa" TransformationMethod="DateTimeDifferenceInDays"> <InputClaims> <InputClaim ClaimTypeReferenceId="lastMfaDate" TransformationClaimType="startDateTime" /> <InputClaim ClaimTypeReferenceId="currentDateTime" TransformationClaimType="endDateTime" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="daysSinceLastMfa" TransformationClaimType="differenceInDays" /> </OutputClaims> </ClaimsTransformation> <!-- 声明转换:判断是否跳过MFA --> <ClaimsTransformation Id="SetSkipMfaIfWithin30Days" TransformationMethod="CompareClaims"> <InputClaims> <InputClaim ClaimTypeReferenceId="daysSinceLastMfa" TransformationClaimType="inputClaim1" /> <InputClaim ClaimTypeReferenceId="30" TransformationClaimType="inputClaim2" /> </InputClaims> <InputParameters> <InputParameter Id="operator" DataType="string" Value="less than" /> <InputParameter Id="outputClaimIfMatched" DataType="boolean" Value="true" /> </InputParameters> <OutputClaims> <OutputClaim ClaimTypeReferenceId="skipMfa" TransformationClaimType="outputClaim" /> </OutputClaims> </ClaimsTransformation>添加条件分支控制MFA执行
修改TOTP相关步骤的执行条件,仅当skipMfa为false时才执行:<OrchestrationStep Order="N" Type="ClaimsExchange" Condition="#{skipMfa} == false"> <ClaimsExchanges> <ClaimsExchange Id="SendTOTP" TechnicalProfileReferenceId="Email-SendTOTP" /> </ClaimsExchanges> </OrchestrationStep>
三、实现“异常行为强制MFA”规则
通过集成Azure AD Identity Protection或自定义风险检测,强制触发MFA:
集成Identity Protection风险信号
在用户读取技术配置中添加风险等级声明,获取用户登录风险信息:<ClaimsProvider> <DisplayName>AAD IDP</DisplayName> <TechnicalProfiles> <TechnicalProfile Id="AAD-UserReadUsingEmailAddress"> <OutputClaims> <OutputClaim ClaimTypeReferenceId="riskLevelAggregated" /> </OutputClaims> </TechnicalProfile> </TechnicalProfiles> </ClaimsProvider>强制MFA的条件判断
修改MFA步骤的执行条件,若检测到中高风险,则忽略skipMfa声明,强制执行MFA:<OrchestrationStep Order="N" Type="ClaimsExchange" Condition="#{skipMfa} == false OR #{riskLevelAggregated} == 'high' OR #{riskLevelAggregated} == 'medium'"> <ClaimsExchanges> <ClaimsExchange Id="SendTOTP" TechnicalProfileReferenceId="Email-SendTOTP" /> </ClaimsExchanges> </OrchestrationStep>自定义风险检测(可选)
若需自定义风险规则(如异地登录、陌生设备),可调用自定义API获取风险信号,再基于结果强制MFA:<TechnicalProfile Id="CustomRiskDetection"> <DisplayName>Custom Risk Detection API</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://your-risk-api.com/detect</Item> <Item Key="AuthenticationType">None</Item> <Item Key="SendClaimsIn">Body</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="ipAddress" /> <InputClaim ClaimTypeReferenceId="deviceId" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="isRisky" /> </OutputClaims> </TechnicalProfile>对应的用户旅程条件:
<OrchestrationStep Order="N" Type="ClaimsExchange" Condition="#{skipMfa} == false OR #{isRisky} == 'true'"> <ClaimsExchanges> <ClaimsExchange Id="SendTOTP" TechnicalProfileReferenceId="Email-SendTOTP" /> </ClaimsExchanges> </OrchestrationStep>
内容的提问来源于stack exchange,提问作者Vamsi Krishna

