如何在登录时同时支持用户名或邮箱两种身份标识?
支持用户名或邮箱登录的实现方案
你说得没错,setting.operatingMode确实只有Username和Email两个选项,没有直接支持同时使用两者的第三种配置。不过我们可以通过自定义验证逻辑和调整技术配置文件的方式来实现用户名或邮箱登录的需求,具体步骤如下:
1. 更新登录标识的ClaimType定义
首先,我们需要修改signInName这个ClaimType的正则表达式,让它同时接受邮箱格式和你定义的用户名格式。这样用户输入的内容会先通过格式校验,确保是合法的用户名或邮箱:
<ClaimType Id="signInName"> <DisplayName>Sign In Name</DisplayName> <DataType>string</DataType> <UserInputType>TextBox</UserInputType> <Restriction> <!-- 正则规则:匹配标准邮箱格式,或1-16位字母/数字/下划线的用户名 --> <Pattern RegularExpression="^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$|^[a-zA-Z0-9_]{1,16}$" HelpText="Please enter a valid username or email address." /> </Restriction> </ClaimType>
你可以根据自己的业务需求调整用户名的正则规则,比如允许的字符范围、长度限制等。
2. 修改本地账户登录的技术配置文件
接下来,调整你的SA-LocalAccount-SignIn技术配置文件:
- 移除
setting.operatingMode元数据项:这个设置会强制系统对signInName字段应用单一格式的验证(要么邮箱要么用户名),和我们的自定义规则冲突,所以必须移除。 - 调整验证流程:添加两个用户读取的验证步骤,先尝试用输入内容作为邮箱查找用户,失败后再尝试作为用户名查找,最后验证密码。
<TechnicalProfile Id="SA-LocalAccount-SignIn"> <DisplayName>Local Account Sign In</DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <Metadata> <Item Key="SignUpTarget">LocalAccountSignUp</Item> <!-- 移除setting.operatingMode,避免强制单一格式验证 --> <Item Key="ContentDefinitionReferenceId">api.localaccountsignin</Item> </Metadata> <OutputClaims> <OutputClaim ClaimTypeReferenceId="signInName" Required="true" /> <OutputClaim ClaimTypeReferenceId="password" Required="true" /> <OutputClaim ClaimTypeReferenceId="objectId" Required="true" /> </OutputClaims> <ValidationTechnicalProfiles> <!-- 先尝试用邮箱查找用户,失败则继续执行下一个验证 --> <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" ContinueOnError="true" /> <!-- 再尝试用用户名查找用户,失败则继续执行下一个验证 --> <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingUsername" ContinueOnError="true" /> <!-- 验证用户输入的密码 --> <ValidationTechnicalProfile ReferenceId="LoginToAzureAD-OIDC" /> </ValidationTechnicalProfiles> <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" /> </TechnicalProfile>
3. 确保用户读取的技术配置文件存在
上面用到的AAD-UserReadUsingEmailAddress和AAD-UserReadUsingUsername是Azure AD B2C的内置技术配置文件,通常默认存在于你的策略中。如果没有的话,你可以添加以下定义:
AAD-UserReadUsingEmailAddress
<TechnicalProfile Id="AAD-UserReadUsingEmailAddress"> <DisplayName>Read user using email address</DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <Metadata> <Item Key="Operation">Read</Item> <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="email" Required="true" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="objectId" /> <!-- 按需添加其他需要返回的用户声明,比如displayName、givenName等 --> </OutputClaims> </TechnicalProfile>
AAD-UserReadUsingUsername
<TechnicalProfile Id="AAD-UserReadUsingUsername"> <DisplayName>Read user using username</DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <Metadata> <Item Key="Operation">Read</Item> <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="signInNames.userName" Required="true" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="objectId" /> <!-- 按需添加其他需要返回的用户声明 --> </OutputClaims> </TechnicalProfile>
工作原理说明
- 移除
setting.operatingMode后,系统不再强制signInName的单一格式,转而使用我们自定义的正则规则校验输入内容。 ContinueOnError="true"属性会让系统在某一步验证失败时继续执行后续的验证步骤:如果用户输入的是邮箱,第一个验证步骤会成功读取用户;如果是用户名,第一个验证失败后,第二个步骤会成功读取用户,最终都会走到密码验证步骤。
内容的提问来源于stack exchange,提问作者nyoung
相关产品推荐
相关产品推荐

