分享方式:


使用 Azure Active Directory B2C 自定義原則收集及操作用戶輸入

Azure Active Directory B2C (Azure AD B2C) 自定義原則可讓您收集使用者輸入。 接著,您可以使用內建方法來操作用戶輸入。

在本文中,您將瞭解如何撰寫自定義原則,以透過圖形使用者介面收集用戶輸入。 接著,您將存取輸入、處理,最後以 JWT 令牌中的宣告的形式傳回這些輸入。 若要完成這項工作,您將:

  • 宣告宣告。 宣告會在 Azure AD B2C 原則執行期間提供數據的暫存記憶體。 它可以儲存使用者的相關信息,例如名字、姓氏或任何其他從使用者或其他系統取得的宣告。 您可以在 Azure AD B2C 自定義原則概觀深入瞭解宣告。

  • 定義技術配置檔。 技術配置檔提供與不同類型的合作對象通訊的介面。 例如,它可讓您與用戶互動以收集數據。

  • 設定宣告轉換,您用來操作宣告的宣告。

  • 設定內容定義。 內容定義會定義要載入的使用者介面。 稍後您可以 藉由提供自己的自定義 HTML 內容來自定義使用者介面

  • 使用自我判斷技術配置檔和 DisplayClaims,設定及顯示使用者介面。

  • 使用協調流程步驟,在指定的序列中呼叫技術配置檔。

必要條件

注意

本文是 Azure Active Directory B2C 操作指南系列 中建立和執行您自己的自訂原則的一部分 。 建議您從第一篇文章開始此系列。

步驟 1 - 宣告宣告

在 objectId 訊息 旁邊 宣告其他宣告:

  1. 在 VS Code 中,開啟 ContosoCustomPolicy.XML 檔案。

  2. 在 區 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 。 這些宣告包括 DataTypeUserInputTypeDisplayName 元素:

  • DataType 指定宣告保留之值的資料類型。 深入瞭解 DataType 元素支援的 資料類型
  • UserInputType 指定要從使用者收集宣告值時,出現在使用者介面上的 UI 控制項。 深入瞭解 Azure AD B2C 支援 的使用者 輸入類型。
  • DisplayName 指定 UI 控制項的標籤,如果您想要從使用者收集宣告的值,該控制項會出現在使用者介面上。

步驟 2 - 定義宣告轉換

ClaimsTransformation 包含用來將指定宣告轉換成另一個宣告的函式。 例如,您可以將字串宣告從小寫變更為大寫。 深入瞭解 Azure AD B2C 支援的宣告轉換。

  1. 在 檔案中 ContosoCustomPolicy.XML ,將 專案新增 <ClaimsTransformations> 為 區段的 BuildingBlocks 子系。

        <ClaimsTransformations>
    
        </ClaimsTransformations>
    
  2. 在 元素內 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 以形成 訊息

步驟 3 - 設定內容定義

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>

步驟 4 - 設定技術設定檔

在自訂原則中, TechnicalProfile 是實作功能的專案。 既然您已定義宣告和宣告轉換,您需要技術設定檔來執行您的定義。 技術設定檔會在 專案內 ClaimsProvider 宣告。

Azure AD B2C 提供一組技術設定檔。 每個技術設定檔都會執行特定角色。 例如,您可以使用 REST 技術設定檔 對服務端點進行 HTTP 呼叫。 您可以使用宣告轉換技術設定檔來執行您在宣告轉換中定義的作業。 深入瞭解 Azure AD B2C 自訂原則所提供的技術設定檔 類型。

設定宣告的值

若要設定 objectId、displayName 訊息 宣告的值 ,您可以設定執行 GenerateRandomObjectIdTransformation、 CreateDisplayNameTransformation CreateMessageTransformation 宣告轉換的技術設定檔 宣告轉換是由 元素中 OutputClaimsTransformations 定義的順序來執行。 例如,它會先建立顯示名稱,然後建立訊息。

  1. 將下列 ClaimsProvider 內容新增為 區段的 ClaimsProviders 子系。

        <ClaimsProvider>
    
            <DisplayName>Technical Profiles to generate claims</DisplayName>
        </ClaimsProvider>
    
    
  2. 若要設定 objectId displayName 訊息 宣告的值 ,請在您剛才建立的專案 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 宣告 ,因此您必須收集然後作為使用者輸入。 若要收集使用者輸入,您可以使用稱為 Self-Asserted 的技術配置檔案類型。 當您設定自我判斷技術設定檔時,您必須將內容定義參考為自我判斷技術設定檔,以負責顯示使用者介面。

  1. 將下列 ClaimsProvider 內容新增為 區段的 ClaimsProviders 子系。

        <ClaimsProvider>
    
            <DisplayName>Technical Profiles to collect user's details </DisplayName>
        </ClaimsProvider>
    
  2. 在您剛才建立的 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 元素中所 定義的順序在螢幕上顯示, 例如指定名稱 ,然後 顯示 Surname

步驟 5 - 定義使用者旅程圖

您可以使用使用者旅程圖來定義呼叫技術設定檔的順序。 您可以使用 OrchestrationSteps 元素來指定使用者旅程圖中的步驟。

以下列程式碼取代 User Journey 的現有內容 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 權杖。

步驟 6 - 更新信賴憑證者

以下列程式碼取代 區段的 RelyingParty 元素內容 OutputClaims

    <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.onmicrosoft.com" 
    PolicyId="B2C_1A_ContosoCustomPolicy" 
    PublicPolicyUri="http://yourtenant.onmicrosoft.com/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 。 瞭解如何 取得您的租使用者名稱

步驟 3 - 上傳自訂原則檔案

請遵循上傳自訂原則檔案 中的 步驟。 如果您要上傳與入口網站中已有相同名稱的檔案,請確定您已選取 [覆寫自訂原則] ,如果檔案已經存在

步驟 4 - 測試自訂原則

  1. 在 [自訂原則] 底下 ,選取 [B2C_1A_CONTOSOCUSTOMPOLICY]。

  2. 針對在 自訂原則的概觀頁面上選取應用程式 ,請選取您先前註冊的 Web 應用程式,例如 webapp1 。 請確定 [選取回復 URL ] 值已設定為 https://jwt.ms

  3. 選取 [ 立即 執行] 按鈕。

  4. 輸入 [指定名稱 ] 和 [姓氏 ],然後選取 [ 繼續 ]。

    screenshot of accepting user inputs in custom policy.

原則完成執行之後,系統會將您重新導向至 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]

下一步

接下來,瞭解: