基于区域的配置的 Azure Active Directory B2C 全局标识框架概念证明
以下部分介绍如何为基于区域的业务流程创建概念证明实现。 可在此处找到已完成的 Azure Active Directory B2C (Azure AD B2C) 自定义策略。
基于区域的方法
每个区域 Azure AD B2C 租户都需要一个 Azure AD B2C 自定义策略,其中包含以下功能:
注册旅程:
- 显示一个屏幕以收集用户的用户名、密码和任何其他属性
- 如果该用户已存在,则通过查询用户-区域映射表来防止注册
- 将用户配置文件写入本地租户
- 将用户的用户名-区域映射写入映射表
- 向应用程序颁发令牌
登录旅程:
- 显示用户名和密码屏幕
- 执行用户名查找并返回其区域
- 执行本地凭据验证或跨租户凭据验证
- 从本地租户或通过跨租户调用读取用户配置文件
- 向应用程序颁发令牌
密码重置旅程:
- 显示一个屏幕以通过电子邮件 OTP 验证用户电子邮件
- 执行用户名查找并返回其区域
- 显示一个屏幕以捕获新密码
- 将新密码写入本地租户或通过跨租户调用写入
- 向应用程序颁发令牌
以下方块图展示了概念证明。 本指南将演示如何配置 Azure AD B2C 租户。 本指南不包括外部 API 层和异地分布式查找表。
先决条件
准备存储层
需要准备一个存储层,它可以存储用户的电子邮件、objectId 和区域。 这样就可以跟踪和查询用户注册的位置。 可以使用 Azure 存储表保存此数据。
准备 API 层
有多个 API 用作概念证明的一部分,以演示基于区域的方法。
验证用户是否已存在
在注册期间使用一个 API 来确定用户是否已存在于任何区域中。
请求将如下所示:
POST /doesUserExistInLookupTable HTTP/1.1
Host: yourapi.com
Content-Type: application/json
{
email: bob@contoso.com
}
如果用户不存在,则响应应该是 HTTP 200。
如果用户存在,则响应应该是 HTTP 409。
记录用户区域映射
在注册期间使用一个 API 来记录用户注册区域。
请求将如下所示:
POST /userToRegionLookup HTTP/1.1
Host: yourapi.com
Authorization Bearer: <token>
Content-Type: application/json
{
"email": "bob@contoso.com"
}
如果用户存在,则响应应该是 HTTP 200。
如果用户存在,则响应应该是 HTTP 409。
返回用户所在的区域
在登录期间使用一个 API 来确定用户是在哪个区域注册的。 它会指示是否需要执行跨租户身份验证。
请求将如下所示:
POST /userToRegionLookup HTTP/1.1
Host: yourapi.com
Authorization Bearer: <token>
Content-Type: application/json
{
"email": "bob@contoso.com"
}
响应应该是 HTTP 200 以及用户注册区域和 objectId。
{
"objectId": "460f9ffb-8b6b-458d-a5a4-b8f3a6816fc2",
"region": "APAC"
}
如果用户不存在或遇到错误,API 应以 HTTP 409 做出响应。
跨租户写入密码
在密码重置流期间使用一个 API 将用户新密码写入他们重置密码所在的不同区域。
请求将如下所示:
POST /writePasswordCrossTenant HTTP/1.1
Host: yourapi.com
Authorization Bearer: <token>
Content-Type: application/json
{
"objectId": "460f9ffb-8b6b-458d-a5a4-b8f3a6816fc2",
"password": "some!strong123STRING"
}
如果过程成功,则响应应该是 HTTP 200;如果出现错误,则响应应该是 HTTP 409。
基于区域的 Azure AD B2C 配置
以下部分准备 Azure AD B2C 租户以跟踪用户注册的区域,并在必要时执行跨租户身份验证或密码重置。
注册自定义策略配置
在注册期间,我们必须确保检查用户不存在于任何其他租户中,并将用户的用户-区域映射写入外部表。
如下所示修改 Azure AD B2C 初学者包中的 LocalAccountSignUpWithLogonEmail
技术配置文件:
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
...
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-getTokenforExternalApiCalls" />
<ValidationTechnicalProfile ReferenceId="REST-doesUserExistInLookupTable" />
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
<ValidationTechnicalProfile ReferenceId="REST-writeUserToRegionMapping" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
ValidationTechnicalProfiles 将执行以下逻辑:
获取令牌以使用
REST-getTokenforExternalApiCalls
技术配置文件调用受保护的 API 终结点。通过安全外部 REST API 终结点验证用户是否已存在于用户-区域映射中:
在所有注册之前进行此 API 调用;为了符合运行时间要求,有必要确保此 API 具有适当的负载均衡、复原能力和故障转移机制。
通过外部 REST API 查询用户-区域映射的技术配置文件示例如下:
<TechnicalProfile Id="REST-doesUserExistInLookupTable "> <DisplayName>User to Region lookup</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://myApi.com/doesUserExistInLookupTable</Item> <Item Key="AuthenticationType">Bearer</Item> <Item Key="UseClaimAsBearerToken">ext_Api_bearerToken</Item> <Item Key="SendClaimsIn">Body</Item> <Item Key="AllowInsecureAuthInProduction">false</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="ext_Api_bearerToken" /> <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="email" /> </InputClaims> <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" /> </TechnicalProfile>
如果用户存在,此 API 应以 HTTP 409 做出响应,并在屏幕上显示相应的错误消息。 否则,如果用户不存在,则以 HTTP 200 做出响应。
通过安全外部 REST API 终结点写入用户-区域映射
在所有注册之前进行此 API 调用;为了符合运行时间要求,有必要确保此 API 具有适当的负载均衡、复原能力和故障转移机制。
通过外部 REST API 写入用户-区域映射的技术配置文件示例如下:
<TechnicalProfile Id="REST-writeUserToRegionMapping"> <DisplayName>User to Region lookup</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://myApi.com/writeUserToRegionMapping</Item> <Item Key="AuthenticationType">Bearer</Item> <Item Key="UseClaimAsBearerToken">ext_Api_bearerToken</Item> <Item Key="SendClaimsIn">Body</Item> <Item Key="AllowInsecureAuthInProduction">false</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="ext_Api_bearerToken" /> <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="email" /> <InputClaim ClaimTypeReferenceId="region" DefaultValue="EMEA" /> <InputClaim ClaimTypeReferenceId="objectId" /> </InputClaims> <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" /> </TechnicalProfile> ```
登录自定义策略配置
在登录期间,我们必须确定用户配置文件位置,并根据其配置文件所在的 Azure AD B2C 租户对其进行身份验证。
修改 Azure AD B2C 初学者包中的 SelfAsserted-LocalAccountSignin-Email
技术配置文件以执行用户区域查找,并在用户来自与他们访问的租户不同的区域时执行跨租户身份验证。 将 ValidationTechnicalProfiles
更新为:
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
...
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-getTokenforExternalApiCalls" />
<ValidationTechnicalProfile ReferenceId="REST-regionLookup" />
<ValidationTechnicalProfile ReferenceId="login-NonInteractive">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>user_region</Value>
<Value>EMEA</Value>
<Action>SkipThisValidationTechnicalProfile</Action>
</Precondition>
</Preconditions>
<ValidationTechnicalProfile ReferenceId="REST-login-NonInteractive-APAC">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>user_region</Value>
<Value>APAC</Value>
<Action>SkipThisValidationTechnicalProfile</Action>
</Precondition>
</Preconditions>
</ValidationTechnicalProfile>
<ValidationTechnicalProfile ReferenceId="REST-fetchUserProfile-APAC">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>user_region</Value>
<Value>APAC</Value>
<Action>SkipThisValidationTechnicalProfile</Action>
</Precondition>
</Preconditions>
</ValidationTechnicalProfile>
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
当用户提交其凭据时,ValidationTechnicalProfiles 将执行以下逻辑:
获取令牌以使用
REST-getTokenforExternalApiCalls
技术配置文件调用受保护的 API 终结点。通过安全外部 REST API 终结点查找用户-区域映射
在所有注册之前进行此 API 调用;为了符合运行时间要求,有必要确保此 API 具有适当的负载均衡、复原能力和故障转移机制。
通过外部 REST API 查询用户-区域映射的技术配置文件示例如下:
<TechnicalProfile Id="REST-regionLookup"> <DisplayName>User to Region lookup</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://myApi.com/userToRegionLookup</Item> <Item Key="AuthenticationType">Bearer</Item> <Item Key="UseClaimAsBearerToken">ext_Api_bearerToken</Item> <Item Key="SendClaimsIn">Body</Item> <Item Key="AllowInsecureAuthInProduction">false</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="ext_Api_bearerToken" /> <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="email" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="user_region" PartnerClaimType="region" /> <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="objectId" /> </OutputClaims> <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" /> </TechnicalProfile>
通过
login-NonInteractive
技术配置文件为在此租户中注册的用户执行本地帐户身份验证。 这是 Azure AD B2C 初学者包中的默认技术配置文件。通过
REST-login-NonInteractive-[region]
技术配置文件按条件为每个相应区域执行跨租户身份验证。这还会从用户主租户获取 MS Graph API 令牌。 在每个具有 MS Graph API 权限的区域租户中完成“原生应用”应用程序注册,以获取以下委托权限:
user.read
。通过外部 REST API 执行用户-区域映射的技术配置文件示例如下:
<TechnicalProfile Id="REST-login-NonInteractive-APAC"> <DisplayName>non interactive authentication to APAC</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://login.partner.microsoftonline.cn/yourAPACb2ctenant.partner.onmschina.cn/oauth2/v2.0/token</Item> <Item Key="AuthenticationType">None</Item> <Item Key="SendClaimsIn">Form</Item> <Item Key="AllowInsecureAuthInProduction">true</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="apac_client_id" PartnerClaimType="client_id" DefaultValue="cf3f6898-9a79-426a-ba16-10e1a377c843" /> <InputClaim ClaimTypeReferenceId="ropc_grant_type" PartnerClaimType="grant_type" DefaultValue="password" /> <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="username" /> <InputClaim ClaimTypeReferenceId="password" /> <InputClaim ClaimTypeReferenceId="scope" DefaultValue="https://microsoftgraph.chinacloudapi.cn/.default" AlwaysUseDefaultValue="true" /> <InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="ext_Api_bearerToken" PartnerClaimType="access_token" /> </OutputClaims> <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" /> </TechnicalProfile>
将
ServiceUrl
中的<yourb2ctenant>
替换为需要作为身份验证目标的租户。使用应用程序注册
ApplicationId
为apac_client_id
输入声明填充DefaultValue
。
使用跨租户 REST API 调用通过
REST-fetchUserProfile-[region]
技术配置文件按条件提取每个相应区域的用户配置文件。通过 MS Graph API 读取用户配置文件的技术配置文件示例如下:
<TechnicalProfile Id="REST-fetchUserProfile-APAC"> <DisplayName>fetch user profile cross tenant</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://microsoftgraph.chinacloudapi.cn/beta/me</Item> <Item Key="AuthenticationType">Bearer</Item> <Item Key="UseClaimAsBearerToken">graph_bearerToken</Item> <Item Key="SendClaimsIn">Body</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="graph_bearerToken" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="id" /> <OutputClaim ClaimTypeReferenceId="givenName" /> <OutputClaim ClaimTypeReferenceId="surName" /> <OutputClaim ClaimTypeReferenceId="displayName" /> <OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="upn" /> <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" /> </OutputClaims> <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" /> </TechnicalProfile>
密码重置自定义策略配置
在密码重置期间,我们必须确定用户配置文件位置,并针对用户配置文件所在的 Azure AD B2C 租户更新密码。
修改 Azure AD B2C 初学者包中的 LocalAccountSignUpWithLogonEmail
技术配置文件以执行用户的用户区域查找,并更新相应租户中的密码。 将 ValidationTechnicalProfiles
更新为:
<TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="ext_Api_bearerToken" DefaultValue="EMEA"/>
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-getTokenforExternalApiCalls">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>user_region</Value>
<Value>EMEA</Value>
<Action>SkipThisValidationTechnicalProfile</Action>
</Precondition>
</Preconditions>
</ValidationTechnicalProfile>
<ValidationTechnicalProfile ReferenceId="REST-regionLookup" />
<ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
当用户提交经过验证的电子邮件以更新其密码时,ValidationTechnicalProfiles 将执行以下逻辑:
获取令牌以调用受保护的 API 终结点
通过安全外部 REST API 终结点查找用户-区域映射
- 此 API 调用在所有密码重置尝试之前进行,确保此 API 具有适当的负载均衡、复原能力和故障转移机制以符合运行时间要求至关重要。
修改 LocalAccountWritePasswordUsingObjectId
技术配置文件,以将新密码写入本地租户或按条件写入跨区域租户。
<TechnicalProfile Id="LocalAccountWritePasswordUsingObjectId">
...
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWritePasswordUsingObjectId">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>user_region</Value>
<Value>EMEA</Value>
<Action>SkipThisValidationTechnicalProfile</Action>
</Precondition>
</Preconditions>
</ValidationTechnicalProfile>
<ValidationTechnicalProfile ReferenceId="REST-UserWritePasswordUsingObjectId-APAC">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>user_region</Value>
<Value>APAC</Value>
<Action>SkipThisValidationTechnicalProfile</Action>
</Precondition>
</Preconditions>
</ValidationTechnicalProfile>
</ValidationTechnicalProfiles>
</TechnicalProfile>
当用户提交新密码时,ValidationTechnicalProfiles 将执行以下逻辑:
如果用户存在于 EMEA 租户(此租户)中,则将用户新密码写入目录。
使用 REST API 调用按条件将新密码写入用户配置文件所在区域的用户配置文件。
<TechnicalProfile Id="REST-UserWritePasswordUsingObjectId-APAC"> <DisplayName>Write password to APAC tenant</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://myApi.com/writePasswordCrossTenant</Item> <Item Key="AuthenticationType">Bearer</Item> <Item Key="UseClaimAsBearerToken">ext_Api_bearerToken</Item> <Item Key="SendClaimsIn">Body</Item> <Item Key="DebugMode">true</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="ext_Api_bearerToken" /> <InputClaim ClaimTypeReferenceId="objectId" /> <InputClaim ClaimTypeReferenceId="newPassword" /> </InputClaims> <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" /> </TechnicalProfile>