Azure-AD B2C 可以使用手机号码作为用户名吗?
Posted
技术标签:
【中文标题】Azure-AD B2C 可以使用手机号码作为用户名吗?【英文标题】:Can Azure-AD B2C use a mobile telephone number as a username? 【发布时间】:2019-05-28 01:36:04 【问题描述】:我们有一个移动应用程序和网站。我们想使用 Azure AD-B2C 进行身份验证。我们不会允许任何第三方身份验证,而是仅在单独的域中使用 Azure AD。
我们更愿意使用用户的电话号码。我的研究表明,此功能是 requested,但目前不存在。
是否有任何解决方法,或者是否已实现此功能但我错过了?
【问题讨论】:
嗨,布莱恩。您可以使用任何内容作为本地帐户的登录名,但您可能必须为此使用自定义策略。您要在注册使用之前验证电话号码吗? 克里斯,确切地说,我们想向手机号码发送一条短信,并让用户验证他们确实拥有手机。我会为那部分使用自定义策略吗? 嗨 Bryan:是的,为此需要自定义策略,请参阅下面的示例策略。 【参考方案1】:这可以实现为 a custom policy,来自 the SocialAndLocalAccountsWithMfa starter pack,其中最终用户的电话号码存储为登录名,并进行了以下更改。
1) 创建名为 PhoneVerified 且类型为 Boolean 的 a custom attribute,以表示最终用户的电话号码是否已经过验证。
2) 在the TrustFrameworkBase.xml file 中,将以下声明类型添加到声明架构中:
我。 phone 声明类型,表示最终用户的电话号码是如何输入的。 E.164 是此声明类型的必需格式:
<ClaimType Id="phone">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
<Restriction>
<Pattern RegularExpression="^\+[0-9]7,15$" HelpText="Please enter a valid phone number." />
</Restriction>
</ClaimType>
二。 signInNames.phoneNumber 声明类型,表示最终用户电话号码的保存方式:
<ClaimType Id="signInNames.phoneNumber">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
</ClaimType>
三。 extension_PhoneVerified 声明类型,表示最终用户的电话号码是否已经过验证:
<ClaimType Id="extension_PhoneVerified">
<DisplayName>Phone Number Verified</DisplayName>
<DataType>boolean</DataType>
</ClaimType>
3) 在 TrustFrameworkBase.xml 文件中,将 LocalAccountSignUpWithLogonPhone 技术配置文件添加到 Local Account 声明提供程序和 AAD- Azure Active Directory 声明提供商的 UserWriteUsingLogonPhone 技术配置文件,用于使用电话号码注册新的最终用户:
<TechnicalProfile Id="LocalAccountSignUpWithLogonPhone">
<DisplayName>Phone signup</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
<Item Key="language.button_continue">Create</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="phone" 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" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonPhone" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserWriteUsingLogonPhone">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" Required="true" />
</InputClaims>
<PersistedClaims>
<!-- Required claims -->
<PersistedClaim ClaimTypeReferenceId="phone" PartnerClaimType="signInNames.phoneNumber" />
<PersistedClaim ClaimTypeReferenceId="newPassword" PartnerClaimType="password"/>
<PersistedClaim ClaimTypeReferenceId="displayName" DefaultValue="unknown" />
<PersistedClaim ClaimTypeReferenceId="passwordPolicies" DefaultValue="DisablePasswordExpiration" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="false" AlwaysUseDefaultValue="true" />
<!-- Optional claims. -->
<PersistedClaim ClaimTypeReferenceId="givenName" />
<PersistedClaim ClaimTypeReferenceId="surname" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="newUser" PartnerClaimType="newClaimsPrincipalCreated" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
最终用户的电话号码保存为 phoneNumber 类型的登录名,并且将最终用户的电话号码是否经过验证设置为 false。
4) 在 TrustFrameworkBase.xml 文件中,将 SelfAsserted-LocalAccountSignin-Phone 技术配置文件添加到 Local Account 声明提供程序,用于使用电话号码登录现有的最终用户:
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Phone">
<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">SignUpWithLogonPhoneExchange</Item>
<Item Key="setting.operatingMode">Username</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
setting.operatingMode 设置设置为 Username,因此登录标识符字段没有电子邮件地址所需的格式。
5) 在 TrustFrameworkBase.xml 文件中,将 AAD-UserReadForPhoneUsingObjectId 技术添加到 Azure Active Directory 声明提供程序,以获取最终用户的对象,包括电话配置文件:
<TechnicalProfile Id="AAD-UserReadForPhoneUsingObjectId">
<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="signInNames.phoneNumber" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneVerified" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
6) 在 TrustFrameworkBase.xml 文件中,将 PhoneFactor-Verify 技术配置文件添加到 Phone Factor 声明提供程序,以验证最终用户的电话号码:
<TechnicalProfile Id="PhoneFactor-Verify">
<DisplayName>PhoneFactor</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.PhoneFactorProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.phonefactor</Item>
<Item Key="ManualPhoneNumberEntryAllowed">false</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CreateUserIdForMFA" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="userIdForMFA" PartnerClaimType="userId" />
<InputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="strongAuthenticationPhoneNumber" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="Verified.strongAuthenticationPhoneNumber" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA" />
</TechnicalProfile>
7) 在 TrustFrameworkBase.xml 文件中,将 UserWritePhoneVerifiedUsingObjectId 技术配置文件添加到 Azure Active Directory 声明提供程序,用于设置是否最终用户的电话号码已被验证为true:
<TechnicalProfile Id="AAD-UserWritePhoneNumberUsingObjectId">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="objectId" />
<PersistedClaim ClaimTypeReferenceId="extension_PhoneVerified" DefaultValue="true" AlwaysUseDefaultValue="true" />
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
注意:必须在 TrustFrameworkBase.xml 文件中添加其他技术配置文件,以允许现有最终用户使用电话号码重置其当前密码,但这有留给读者作为练习。
8) 在 TrustFrameworkBase.xml 文件中,添加 SignUpOrSignInForPhone 用户旅程,允许新最终用户使用电话号码或现有终端注册-user 使用电话号码登录,然后验证最终用户的电话号码。
<UserJourney Id="SignUpOrSignInForPhone">
<OrchestrationSteps>
<!-- Display the sign-up or sign-in interaction so an existing end-user can sign in with a phone number -->
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninPhoneExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninPhoneExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Phone" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- A new end-user has selected to sign up with a phone number -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonPhoneExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonPhone" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Read the user object -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadForPhoneUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- If the end-user's phone number hasn't been verified, then verify it during sign-up or following the first sign-in with an unverified phone number -->
<OrchestrationStep Order="4" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-Verify" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Set whether the end-user's phone number has been verified to true -->
<OrchestrationStep Order="5" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>extension_PhoneVerified</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>isActiveMFASession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserWriteWithObjectId" TechnicalProfileReferenceId="AAD-UserWritePhoneVerifiedUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="6" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
</UserJourney>
9) 创建名为 SignUpOrSignInForPhone.xml(或类似名称)的 a relying party file 并引用 SignUpOrSignInForPhone 用户旅程:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<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="yourtenant.onmicrosoft.com"
PolicyId="B2C_1A_signup_signin_phone"
PublicPolicyUri="http://yourtenant.onmicrosoft.com/B2C_1A_signup_signin_phone">
<BasePolicy>
<TenantId>yourtenant.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
</BasePolicy>
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignInForPhone" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="signInNames.phoneNumber" PartnerClaimType="phone_number" />
<OutputClaim ClaimTypeReferenceId="extension_PhoneNumber" PartnerClaimType="phone_number_verified" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>
输出给依赖方的令牌声明包括:
我。 phone_number 声明,代表最终用户的电话号码。
二。 phone_number_verified 声明表示最终用户的电话号码是否已经过验证。
【讨论】:
克里斯,非常感谢你。太棒了!! 嗨,克里斯,您能帮我为上述实施添加自定义密码重置策略吗(手机号登录注册) 克里斯,这引用了似乎不存在的“AAD-UserWritePhoneVerifiedUsingObjectId”。这应该是“AAD-UserWritePhoneNumberUsingObjectId”吗? 嗨,克里斯,帮了大忙。要确认是否必须添加额外的验证来检查移动电话号码?据我所知,这适用于任何电话号码,那么验证是否会尝试发送到非手机号码? 仅供参考:Microsoft 建议不要修改 TrustFrameworkBase.xml。您应该始终在基础之上创建一个扩展文件。【参考方案2】:终于正式支持了:
Azure AD B2C now supports phone-based sign-in and sign-up for apps using B2C custom policy
【讨论】:
【参考方案3】:我可以使用手机号码在内置登录或注册策略中注册为本地用户名。流程如下:
结果是:
或者您也可以像 Chris Padgett 所说的那样使用自定义策略来实现。
【讨论】:
我们还希望能够通过向用户发送文本并让他们采取一些操作(例如点击 URL)来验证电话号码。自定义政策可以做到这一点吗? @BryanSchmiedeler,您可以在内置策略中启用 MFA。详情可参考here。 太棒了。现在,如果我想添加重置密码策略怎么办。您能否为此与我分享步骤和自定义政策。以上是关于Azure-AD B2C 可以使用手机号码作为用户名吗?的主要内容,如果未能解决你的问题,请参考以下文章
用于Azure B2C acces令牌的Exchange Facebook SDK acces令牌
如何使用 Azure AD B2C 获取 Facebook 个人资料图片