借助 Azure Active Directory B2C (Azure AD B2C) 自定义策略,可以收集用户输入。 然后,可以使用内置方法来操作用户输入。
在本文中,你将了解如何通过图形用户界面写入收集用户输入的自定义策略。 然后,你将访问输入,然后处理,最后以 JWT 中的声明的形式返回它们。 要完成此任务,你将:
宣告索赔。 声明可在 Azure AD B2C 策略执行过程中提供数据的临时存储。 它可存储用户的相关信息,例如名字、姓氏,或者从用户或其他系统获得的任何其他声明。 可以在 Azure AD B2C 自定义策略概述中详细了解声明。
定义技术概况。 技术配置文件提供了与不同类型的参与方进行通信的接口。 例如,它允许你与用户交互以收集数据。
配置声明转换,以操控您作出的声明。
配置内容定义。 内容定义可定义要加载的用户界面。 稍后,可以通过提供自己的自定义 HTML 内容来自定义用户界面。
使用自断言技术配置文件和 DisplayClaims 配置和显示用户的用户界面。
使用业务流程步骤在给定序列中调用技术配置文件。
如果您还没有 Azure AD B2C 租户,请创建一个链接到您的 Azure 订阅的 Azure AD B2C 租户。
必须在计算机上安装 Visual Studio Code (VS Code)。
完成编写第一个 Azure AD B2C 自定义策略 - Hello World!中的步骤。 本文是创建和运行自己的自定义策略操作指南系列教程的一部分。
备注
本文是《在 Azure Active Directory B2C 中创建和运行自己的自定义策略操作指南系列教程》的一部分。 建议从第一篇文章开始本系列教程。
将附加声明与 objectId 和 message 一起声明:
在 VS Code 中,打开
ContosoCustomPolicy.XML
文件。在
ClaimsSchema
部分中,添加以下 ClaimType 声明:<ClaimType Id="givenName"> <DisplayName>Given Name</DisplayName> <DataType>string</DataType> <UserHelpText>Your given name (also known as first name).</UserHelpText> <UserInputType>TextBox</UserInputType> </ClaimType> <ClaimType Id="surname"> <DisplayName>Surname</DisplayName> <DataType>string</DataType> <UserHelpText>Your surname (also known as family name or last name).</UserHelpText> <UserInputType>TextBox</UserInputType> </ClaimType> <ClaimType Id="displayName"> <DisplayName>Display Name</DisplayName> <DataType>string</DataType> <UserHelpText>Your display name.</UserHelpText> <UserInputType>TextBox</UserInputType> </ClaimType>
我们已声明三种声明类型:givenName、surname 和 displayName。 这些声明包括 DataType
、UserInputType
和 DisplayName
元素:
- DataType 指定了声明保留的值的数据类型。 详细了解 DataType 元素支持的数据类型。
- 如果想要从用户收集声明的值,UserInputType 指定了用户界面上显示的 UI 控件。 详细了解 Azure AD B2C 支持的用户输入类型。
- DisplayName 指定了用户界面上的 UI 控件标签,以便在需要从用户处收集声明值时显示。
ClaimsTransformation 包含用于将给定声明转换为另一个声明的函数。 例如,可以将字符串声明从小写更改为大写。 详细了解 Azure AD B2C 支持的声明转换。
在
ContosoCustomPolicy.XML
文件中,添加<ClaimsTransformations>
元素作为BuildingBlocks
部分的子级。<ClaimsTransformations> </ClaimsTransformations>
在
ClaimsTransformations
元素中添加以下代码:<ClaimsTransformation Id="GenerateRandomObjectIdTransformation" TransformationMethod="CreateRandomString"> <InputParameters> <InputParameter Id="randomGeneratorType" DataType="string" Value="GUID"/> </InputParameters> <OutputClaims> <OutputClaim ClaimTypeReferenceId="objectId" TransformationClaimType="outputClaim"/> </OutputClaims> </ClaimsTransformation> <ClaimsTransformation Id="CreateDisplayNameTransformation" TransformationMethod="FormatStringMultipleClaims"> <InputClaims> <InputClaim ClaimTypeReferenceId="givenName" TransformationClaimType="inputClaim1"/> <InputClaim ClaimTypeReferenceId="surname" TransformationClaimType="inputClaim2"/> </InputClaims> <InputParameters> <InputParameter Id="stringFormat" DataType="string" Value="{0} {1}"/> </InputParameters> <OutputClaims> <OutputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="outputClaim"/> </OutputClaims> </ClaimsTransformation> <ClaimsTransformation Id="CreateMessageTransformation" TransformationMethod="FormatStringClaim"> <InputClaims> <InputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="inputClaim"/> </InputClaims> <InputParameters> <InputParameter Id="stringFormat" DataType="string" Value="Hello {0}"/> </InputParameters> <OutputClaims> <OutputClaim ClaimTypeReferenceId="message" TransformationClaimType="outputClaim"/> </OutputClaims> </ClaimsTransformation>
我们配置了三种声明转换:
GenerateRandomObjectIdTransformation 可生成由 CreateRandomString 方法指定的随机字符串。 objectId 声明根据
OutputClaim
元素指定的生成字符串被更新。CreateDisplayNameTransformation 可连接 givenName 和 surname,以构成 displayName 格式。
CreateMessageTransformation 可连接 Hello 和 displayName,以构成 消息。
使用 ContentDefinitions,可以指定 HTML 模板的 URL,这些模板控制你向用户显示的网页布局。 可以为每个步骤指定特定的用户界面,例如登录或注册、密码重置或错误页。
要添加内容定义,请在 BuildingBlocks
文件的 ContosoCustomPolicy.XML
部分中添加以下代码:
<ContentDefinitions>
<ContentDefinition Id="SelfAssertedContentDefinition">
<LoadUri>~/tenant/templates/AzureBlue/selfAsserted.cshtml</LoadUri>
<RecoveryUri>~/common/default_page_error.html</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.7</DataUri>
</ContentDefinition>
</ContentDefinitions>
在自定义策略中,TechnicalProfile 是实现功能的元素。 既然你已定义了声明和声明转换,那么你需要技术简介来执行这些定义。 技术配置文件在 ClaimsProvider
元素中声明。
Azure AD B2C 提供了一组技术配置文件。 每个技术配置文件都执行特定角色。 例如,使用 REST 技术配置文件可对服务终结点进行 HTTP 调用。 可以使用声明转换技术配置文件来执行在声明转换中定义的操作。 详细了解 Azure AD B2C 自定义策略提供的 技术配置文件类型。
要设置 objectId、displayName 和 message 声明的值,请配置执行 GenerateRandomObjectIdTransformation、CreateDisplayNameTransformation 和 CreateMessageTransformation 声明转换的技术配置文件。 声明转换按在 OutputClaimsTransformations
元素中定义的顺序执行。 例如,它首先创建显示名称,然后创建消息。
将以下
ClaimsProvider
添加为ClaimsProviders
部分的子项。<ClaimsProvider> <DisplayName>Technical Profiles to generate claims</DisplayName> </ClaimsProvider>
要设置 objectId、displayName 和 message 声明的值,请在刚刚创建的
ClaimsProvider
元素中添加以下代码:<!--<ClaimsProvider>--> <TechnicalProfiles> <TechnicalProfile Id="ClaimGenerator"> <DisplayName>Generate Object ID, displayName and message Claims Technical Profile.</DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> <OutputClaims> <OutputClaim ClaimTypeReferenceId="objectId"/> <OutputClaim ClaimTypeReferenceId="displayName"/> <OutputClaim ClaimTypeReferenceId="message"/> </OutputClaims> <OutputClaimsTransformations> <OutputClaimsTransformation ReferenceId="GenerateRandomObjectIdTransformation"/> <OutputClaimsTransformation ReferenceId="CreateDisplayNameTransformation"/> <OutputClaimsTransformation ReferenceId="CreateMessageTransformation"/> </OutputClaimsTransformations> </TechnicalProfile> </TechnicalProfiles> <!--</ClaimsProvider>-->
你会根据 givenName 和 surname 生成 displayName 声明,因此需要收集它们作为用户输入。 若要收集用户输入的内容,请使用一种名为“自断言”的技术配置文件。 配置自断言技术配置文件时,由于自断言技术配置文件负责显示用户界面,因此需要引用内容定义。
将以下
ClaimsProvider
添加为ClaimsProviders
部分的子项。<ClaimsProvider> <DisplayName>Technical Profiles to collect user's details </DisplayName> </ClaimsProvider>
在刚刚创建的
ClaimsProvider
元素中添加以下代码:<TechnicalProfiles> <TechnicalProfile Id="UserInformationCollector"> <DisplayName>Collect User Input Technical Profile</DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> <Metadata> <Item Key="ContentDefinitionReferenceId">SelfAssertedContentDefinition</Item> </Metadata> <DisplayClaims> <DisplayClaim ClaimTypeReferenceId="givenName" Required="true"/> <DisplayClaim ClaimTypeReferenceId="surname" Required="true"/> </DisplayClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="givenName"/> <OutputClaim ClaimTypeReferenceId="surname"/> </OutputClaims> </TechnicalProfile> </TechnicalProfiles>
请注意与 givenName 和 surname 声明相关的两个显示声明。 这两个声明都标记为必需,因此用户必须先输入值,然后才能提交向其显示的表单。 声明按照 DisplayClaims 元素中定义的顺序显示在屏幕上,例如,首先显示名字,然后显示姓氏。
使用用户旅程来定义调用技术配置文件的顺序。 使用 OrchestrationSteps
元素指定用户旅程中的步骤。
将 HelloWorldJourney
用户旅程的现有内容替换为以下代码:
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="GetUserInformationClaimsExchange" TechnicalProfileReferenceId="UserInformationCollector"/>
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="GetMessageClaimsExchange" TechnicalProfileReferenceId="ClaimGenerator"/>
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer"/>
</OrchestrationSteps>
根据业务流程步骤,我们收集用户输入、为 objectId、 displayName 和 消息 声明设置值,最后发送 JWT。
将 OutputClaims
部分的 RelyingParty
元素内容替换为以下代码:
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
<OutputClaim ClaimTypeReferenceId="displayName"/>
<OutputClaim ClaimTypeReferenceId="message"/>
完成步骤 6 后,ContosoCustomPolicy.XML
文件外观应类似于以下代码:
<?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.partner.onmschina.cn"
PolicyId="B2C_1A_ContosoCustomPolicy"
PublicPolicyUri="http://yourtenant.partner.onmschina.cn/B2C_1A_ContosoCustomPolicy">
<BuildingBlocks>
<ClaimsSchema>
<ClaimType Id="objectId">
<DisplayName>unique object Id for subject of the claims being returned</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="message">
<DisplayName>Will hold Hello World message</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="givenName">
<DisplayName>Given Name</DisplayName>
<DataType>string</DataType>
<UserHelpText>Your given name (also known as first name).</UserHelpText>
<UserInputType>TextBox</UserInputType>
</ClaimType>
<ClaimType Id="surname">
<DisplayName>Surname</DisplayName>
<DataType>string</DataType>
<UserHelpText>Your surname (also known as family name or last name).</UserHelpText>
<UserInputType>TextBox</UserInputType>
</ClaimType>
<ClaimType Id="displayName">
<DisplayName>Display Name</DisplayName>
<DataType>string</DataType>
<UserHelpText>Your display name.</UserHelpText>
<UserInputType>TextBox</UserInputType>
</ClaimType>
</ClaimsSchema>
<ClaimsTransformations>
<ClaimsTransformation Id="GenerateRandomObjectIdTransformation" TransformationMethod="CreateRandomString">
<InputParameters>
<InputParameter Id="randomGeneratorType" DataType="string" Value="GUID"/>
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" TransformationClaimType="outputClaim"/>
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="CreateDisplayNameTransformation" TransformationMethod="FormatStringMultipleClaims">
<InputClaims>
<InputClaim ClaimTypeReferenceId="givenName" TransformationClaimType="inputClaim1"/>
<InputClaim ClaimTypeReferenceId="surname" TransformationClaimType="inputClaim2"/>
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormat" DataType="string" Value="{0} {1}"/>
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="outputClaim"/>
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="CreateMessageTransformation" TransformationMethod="FormatStringClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="inputClaim"/>
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormat" DataType="string" Value="Hello {0}"/>
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="message" TransformationClaimType="outputClaim"/>
</OutputClaims>
</ClaimsTransformation>
</ClaimsTransformations>
<ContentDefinitions>
<ContentDefinition Id="SelfAssertedContentDefinition">
<LoadUri>~/tenant/templates/AzureBlue/selfAsserted.cshtml</LoadUri>
<RecoveryUri>~/common/default_page_error.html</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.7</DataUri>
</ContentDefinition>
</ContentDefinitions>
</BuildingBlocks>
<!--Claims Providers Here-->
<ClaimsProviders>
<ClaimsProvider>
<DisplayName>Token Issuer</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="JwtIssuer">
<DisplayName>JWT Issuer</DisplayName>
<Protocol Name="None"/>
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="client_id">{service:te}</Item>
<Item Key="issuer_refresh_token_user_identity_claim_type">objectId</Item>
<Item Key="SendTokenResponseBodyWithJsonNumbers">true</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer"/>
<Key Id="issuer_refresh_token_key" StorageReferenceId="B2C_1A_TokenEncryptionKeyContainer"/>
</CryptographicKeys>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Trustframework Policy Engine TechnicalProfiles</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="TpEngine_c3bd4fe2-1775-4013-b91d-35f16d377d13">
<DisplayName>Trustframework Policy Engine Default Technical Profile</DisplayName>
<Protocol Name="None"/>
<Metadata>
<Item Key="url">{service:te}</Item>
</Metadata>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Claim Generator Technical Profiles</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="ClaimGenerator">
<DisplayName>Generate Object ID, displayName and message Claims Technical Profile.</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId"/>
<OutputClaim ClaimTypeReferenceId="displayName"/>
<OutputClaim ClaimTypeReferenceId="message"/>
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="GenerateRandomObjectIdTransformation"/>
<OutputClaimsTransformation ReferenceId="CreateDisplayNameTransformation"/>
<OutputClaimsTransformation ReferenceId="CreateMessageTransformation"/>
</OutputClaimsTransformations>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Technical Profiles to collect user's details</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="UserInformationCollector">
<DisplayName>Collect User Input Technical Profile</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<Metadata>
<Item Key="ContentDefinitionReferenceId">SelfAssertedContentDefinition</Item>
</Metadata>
<DisplayClaims>
<DisplayClaim ClaimTypeReferenceId="givenName" Required="true"/>
<DisplayClaim ClaimTypeReferenceId="surname" Required="true"/>
</DisplayClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="givenName"/>
<OutputClaim ClaimTypeReferenceId="surname"/>
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
<UserJourneys>
<UserJourney Id="HelloWorldJourney">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="GetUserInformationClaimsExchange" TechnicalProfileReferenceId="UserInformationCollector"/>
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="GetMessageClaimsExchange" TechnicalProfileReferenceId="ClaimGenerator"/>
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer"/>
</OrchestrationSteps>
</UserJourney>
</UserJourneys>
<RelyingParty><!--
Relying Party Here that's your policy’s entry point
Specify the User Journey to execute
Specify the claims to include in the token that is returned when the policy runs
-->
<DefaultUserJourney ReferenceId="HelloWorldJourney"/>
<TechnicalProfile Id="HelloWorldPolicyProfile">
<DisplayName>Hello World Policy Profile</DisplayName>
<Protocol Name="OpenIdConnect"/>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
<OutputClaim ClaimTypeReferenceId="displayName"/>
<OutputClaim ClaimTypeReferenceId="message"/>
</OutputClaims>
<SubjectNamingInfo ClaimType="sub"/>
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>
如果尚未这样做,请将 yourtenant
替换为租户名称的子域部分,例如 contoso
。 了解如何获取租户名称。
按照上传自定义策略文件中的步骤进行操作。 如果要上传与门户中已有的文件同名的文件,请确保选择“覆盖自定义策略(如果已存在)”。
在“自定义策略”下,选择“B2C_1A_CONTOSOCUSTOMPOLICY”。
对于自定义策略概述页面上的“选择应用程序”,选择先前注册的 Web 应用程序,如“webapp1”。 确保将“选择回复 URL”的值设置为“
https://jwt.ms
”。单击“立即运行”按钮。
输入名和姓,然后选择“继续”。
策略完成执行后,会重定向到 https://jwt.ms
并看到解码的 JWT。 它类似于以下 JWT 代码片段:
{
"typ": "JWT",
"alg": "RS256",
"kid": "pxLOMWFg...."
}.{
...
"sub": "c7ae4515-f7a7....",
...
"acr": "b2c_1a_contosocustompolicy",
...
"name": "Maurice Paulet",
"message": "Hello Maurice Paulet"
}.[Signature]
接下来,了解:
关于 Azure AD B2C 自定义策略中技术配置文件的类型。