在 Azure Active Directory B2C 中設定資源擁有者密碼認證流程

開始之前,請使用 [選擇原則類型 選取器] 來選擇您要設定的原則類型。 Azure Active Directory B2C 提供兩種方法來定義使用者如何與您的應用程式互動:透過預先 定義的使用者流程 ,或透過完全可設定 的自定義原則。 本文中每個方法所需的步驟都不同。

在 Azure Active Directory B2C(Azure AD B2C)中,資源擁有者密碼認證 (ROPC) 流程是 OAuth 標準驗證流程。 在此流程中,應用程式也稱為信賴憑證者,會交換令牌的有效認證。 認證包含使用者識別碼和密碼。 傳回的令牌是標識碼令牌、存取令牌和重新整理令牌。

警告

我們建議您 不要 使用 ROPC 流程。 在大部分情況下,有更安全的替代方案可供使用,並建議使用。 此流程在應用程式中需要高度信任,而且具有在其他流程中不存在的風險。 只有當其他更安全的流程無法運作時,才應該使用此流程。

ROPC 流程附註

在 Azure Active Directory B2C(Azure AD B2C)中,支援下列選項:

  • Native Client:在驗證期間,會在程式代碼在使用者端裝置上執行時發生用戶互動。 裝置可以是在原生作業系統中執行的行動應用程式,例如 Android 和 iOS。
  • 公用用戶端流程:只有應用程式收集的用戶認證才會在 API 呼叫中傳送。 不會傳送應用程式的認證。
  • 新增宣告:可以變更標識碼令牌內容以新增宣告。

不支援下列流程:

  • 伺服器對伺服器:身分識別保護系統需要從呼叫端 (原生用戶端) 收集的可靠IP位址,作為互動的一部分。 在伺服器端 API 呼叫中,只會使用伺服器的 IP 位址。 如果超過失敗驗證的動態閾值,身分識別保護系統可能會將重複的IP位址識別為攻擊者。
  • 機密用戶端流程:已驗證應用程式用戶端標識碼,但不會驗證應用程式密碼。

使用 ROPC 流程時,請考慮下列事項:

  • 當需要使用者互動的驗證流程中斷時,ROPC 將無法運作。 例如,當密碼已過期或需要變更時, 需要多重要素驗證 ,或在登入期間需要收集更多資訊時(例如,使用者同意)。
  • ROPC 僅支援本機帳戶。 用戶無法使用 Microsoft、Google+、Twitter、AD-FS 或 Facebook 等同盟識別提供者登入
  • 會話管理,包括 讓我保持登入 (KMSI)不適用。

註冊應用程式

若要在您的 Azure AD B2C 租用戶中註冊應用程式,您可以使用我們新的整合應用程式註冊體驗,或使用舊版應用程式 (舊版) 體驗。 深入了解新體驗

  1. 登入 Azure 入口網站
  2. 請確定您使用的是包含 Azure AD B2C 租使用者的目錄:
    1. 在入口網站工具列中選取 [ 目錄 + 訂用帳戶 ] 圖示。
    2. 在入口 網站設定 |[目錄 + 訂用帳戶 ] 頁面,在 [ 目錄名稱 ] 列表中尋找您的 Azure AD B2C 目錄,然後選取 [ 切換]。
  3. 在 Azure 入口網站 中,搜尋並選取 [Azure AD B2C]
  4. 選取 [應用程式註冊],然後選取 [新增註冊]
  5. 輸入 應用程式的 [名稱 ]。 例如, ROPC_Auth_app
  6. 保留其他值,然後選取 [ 註冊]。
  7. 記錄應用程式 (用戶端) 識別碼,以供後續步驟使用。
  8. 在 [管理] 底下,選取 [驗證]
  9. 選取 [ 試用新體驗 ](如所示)。
  10. 在 [進階設定] 和 [啟用下列行動和桌面流程] 區段下,選取 [] 將應用程式視為公用用戶端。 ROPC 流程需要此設定。
  11. 選取 [儲存]。
  12. 在左側功能表中,選取 [ 指令清單 ] 以開啟指令清單編輯器。
  13. oauth2AllowImplicitFlow 屬性設定為 true
    "oauth2AllowImplicitFlow": true,
    
  14. 選取 [儲存]。

建立資源擁有者使用者流程

  1. 以 Azure AD B2C 租使用者的全域管理員身分登入 Azure 入口網站
  2. 如果您有多個租使用者的存取權,請選取頂端功能表中的 設定 圖示,從 [目錄 + 訂用帳戶] 功能表切換至您的 Azure AD B2C 租使用者。
  3. 在 Azure 入口網站中,搜尋並選取 [Azure AD B2C]
  4. 選取 [ 使用者流程],然後選取 [ 新增使用者流程]。
  5. 選取 [使用資源擁有者密碼認證登入] [ROPC]。
  6. 在 [版本] 底下,確定已選取 [預覽],然後選取 [建立]。
  7. 提供使用者流程的名稱,例如 ROPC_Auth
  8. 在 [應用程式宣告] 底下,選取 [顯示更多]。
  9. 選取應用程式所需的應用程式宣告,例如顯示名稱、電子郵件地址和識別提供者。
  10. 選取確定,然後選取建立

先決條件

如果您尚未這麼做,請了解開始使用 Active Directory B2C 中的自定義原則入門套件。

建立資源擁有者原則

  1. 開啟 TrustFrameworkExtensions.xml 檔案。

  2. 如果尚未存在,請新增 ClaimsSchema 元素及其子元素作為 BuildingBlocks 元素底下的第一個專案:

    <ClaimsSchema>
      <ClaimType Id="logonIdentifier">
        <DisplayName>User name or email address that the user can use to sign in</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
      <ClaimType Id="resource">
        <DisplayName>The resource parameter passes to the ROPC endpoint</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
      <ClaimType Id="refreshTokenIssuedOnDateTime">
        <DisplayName>An internal parameter used to determine whether the user should be permitted to authenticate again using their existing refresh token.</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
      <ClaimType Id="refreshTokensValidFromDateTime">
        <DisplayName>An internal parameter used to determine whether the user should be permitted to authenticate again using their existing refresh token.</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
    </ClaimsSchema>
    
  3. 在 ClaimsSchema 之後,將 ClaimsTransformations 元素及其子元素新增至 BuildingBlocks 元素:

    <ClaimsTransformations>
      <ClaimsTransformation Id="CreateSubjectClaimFromObjectID" TransformationMethod="CreateStringClaim">
        <InputParameters>
          <InputParameter Id="value" DataType="string" Value="Not supported currently. Use oid claim." />
        </InputParameters>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="sub" TransformationClaimType="createdClaim" />
        </OutputClaims>
      </ClaimsTransformation>
    
      <ClaimsTransformation Id="AssertRefreshTokenIssuedLaterThanValidFromDate" TransformationMethod="AssertDateTimeIsGreaterThan">
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="refreshTokenIssuedOnDateTime" TransformationClaimType="leftOperand" />
          <InputClaim ClaimTypeReferenceId="refreshTokensValidFromDateTime" TransformationClaimType="rightOperand" />
        </InputClaims>
        <InputParameters>
          <InputParameter Id="AssertIfEqualTo" DataType="boolean" Value="false" />
          <InputParameter Id="AssertIfRightOperandIsNotPresent" DataType="boolean" Value="true" />
        </InputParameters>
      </ClaimsTransformation>
    </ClaimsTransformations>
    
  4. 找出具有 DisplayNameLocal Account SignIn ClaimsProvider 元素,並新增下列技術配置檔:

    <TechnicalProfile Id="ResourceOwnerPasswordCredentials-OAUTH2">
      <DisplayName>Local Account SignIn</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <Metadata>
        <Item Key="UserMessageIfClaimsPrincipalDoesNotExist">We can't seem to find your account</Item>
        <Item Key="UserMessageIfInvalidPassword">Your password is incorrect</Item>
        <Item Key="UserMessageIfOldPasswordUsed">Looks like you used an old password</Item>
        <Item Key="DiscoverMetadataByTokenIssuer">true</Item>
        <Item Key="ValidTokenIssuerPrefixes">https://sts.windows.net/</Item>
        <Item Key="METADATA">https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration</Item>
        <Item Key="authorization_endpoint">https://login.microsoftonline.com/{tenant}/oauth2/token</Item>
        <Item Key="response_types">id_token</Item>
        <Item Key="response_mode">query</Item>
        <Item Key="scope">email openid</Item>
        <Item Key="grant_type">password</Item>
      </Metadata>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="logonIdentifier" PartnerClaimType="username" Required="true" DefaultValue="{OIDC:Username}"/>
        <InputClaim ClaimTypeReferenceId="password" Required="true" DefaultValue="{OIDC:Password}" />
        <InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" />
        <InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" />
        <InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" />
        <InputClaim ClaimTypeReferenceId="client_id" DefaultValue="ProxyIdentityExperienceFrameworkAppId" />
        <InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="IdentityExperienceFrameworkAppId" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" />
        <OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="upn" />
      </OutputClaims>
      <OutputClaimsTransformations>
        <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID" />
      </OutputClaimsTransformations>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
    </TechnicalProfile>
    

    將 client_idDefaultValue 取代為您在必要條件教學課程中建立的 ProxyIdentityExperienceFramework 應用程式的應用程式識別符。 然後將 resource_idDefaultValue 取代為您在必要條件教學課程中也建立的 IdentityExperienceFramework 應用程式的應用程式識別碼。

  5. 將下列 ClaimsProvider 元素及其技術配置檔新增至 ClaimsProviders 元素:

    <ClaimsProvider>
      <DisplayName>Azure Active Directory</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="AAD-UserReadUsingObjectId-CheckRefreshTokenDate">
          <Metadata>
            <Item Key="Operation">Read</Item>
            <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
          </Metadata>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="objectId" Required="true" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="refreshTokensValidFromDateTime" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="AssertRefreshTokenIssuedLaterThanValidFromDate" />
            <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID" />
          </OutputClaimsTransformations>
          <IncludeTechnicalProfile ReferenceId="AAD-Common" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    
    <ClaimsProvider>
      <DisplayName>Session Management</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="SM-RefreshTokenReadAndSetup">
          <DisplayName>Trustframework Policy Engine Refresh Token Setup Technical Profile</DisplayName>
          <Protocol Name="None" />
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="refreshTokenIssuedOnDateTime" />
          </OutputClaims>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    
    <ClaimsProvider>
      <DisplayName>Token Issuer</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="JwtIssuer">
          <Metadata>
            <!-- Point to the redeem refresh token user journey-->
            <Item Key="RefreshTokenUserJourneyId">ResourceOwnerPasswordCredentials-RedeemRefreshToken</Item>
          </Metadata>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    
  6. 將 UserJourneys 元素及其子元素新增至 TrustFrameworkPolicy 元素:

    <UserJourney Id="ResourceOwnerPasswordCredentials">
      <PreserveOriginalAssertion>false</PreserveOriginalAssertion>
      <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="ResourceOwnerFlow" TechnicalProfileReferenceId="ResourceOwnerPasswordCredentials-OAUTH2" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
      </OrchestrationSteps>
    </UserJourney>
    <UserJourney Id="ResourceOwnerPasswordCredentials-RedeemRefreshToken">
      <PreserveOriginalAssertion>false</PreserveOriginalAssertion>
      <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="RefreshTokenSetupExchange" TechnicalProfileReferenceId="SM-RefreshTokenReadAndSetup" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="CheckRefreshTokenDateFromAadExchange" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId-CheckRefreshTokenDate" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
      </OrchestrationSteps>
    </UserJourney>
    
  7. 在 Azure AD B2C 租使用者的 [ 自定義原則] 頁面上,選取 [ 上傳原則]。

  8. 如果原則存在,請啟用 [覆寫原則],然後流覽至並選取 TrustFrameworkExtensions.xml 檔案。

  9. 選取上傳

建立信賴憑證者檔案

接下來,更新起始您所建立使用者旅程圖的信賴憑證者檔案:

  1. 在工作目錄中建立 SignUpOrSignin.xml 檔案的複本,並將它重新命名為 ROPC_Auth.xml

  2. 開啟新檔案,並將 TrustFrameworkPolicyPolicyId 屬性值變更為唯一值。 原則標識碼是您原則的名稱。 例如, B2C_1A_ROPC_Auth

  3. 將 DefaultUserJourney 中 ReferenceId 屬性的值變更為 ResourceOwnerPasswordCredentials

  4. OutputClaims 元素變更為只包含下列宣告:

    <OutputClaim ClaimTypeReferenceId="sub" />
    <OutputClaim ClaimTypeReferenceId="objectId" />
    <OutputClaim ClaimTypeReferenceId="displayName" DefaultValue="" />
    <OutputClaim ClaimTypeReferenceId="givenName" DefaultValue="" />
    <OutputClaim ClaimTypeReferenceId="surname" DefaultValue="" />
    
  5. 在 Azure AD B2C 租使用者的 [ 自定義原則] 頁面上,選取 [ 上傳原則]。

  6. 如果原則存在,請啟用 [覆寫] 原則,然後流覽至並選取 ROPC_Auth.xml 檔案。

  7. 選取上傳

測試 ROPC 流程

使用您慣用的 API 開發應用程式來產生 API 呼叫,並檢閱回應以偵錯您的原則。 以下列資訊作為 POST 要求的本文,建構類似此範例的呼叫:

https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/B2C_1A_ROPC_Auth/oauth2/v2.0/token

  • 將 取代 <tenant-name> 為您的 Azure AD B2C 租用戶名稱。
  • 將取代 B2C_1A_ROPC_Auth 為您資源擁有者密碼認證原則的完整名稱。
機碼
username user-account
password password1
grant_type password
範圍 (scope) openid application-id offline_access
client_id application-id
response_type token id_token
  • 將取代 user-account 為您租使用者中的用戶帳戶名稱。
  • 將取代 password1 為用戶帳戶的密碼。
  • 將取代application-id為來自ROPC_Auth_app註冊的應用程式標識碼。
  • 如果您想要接收重新整理令牌,Offline_access 是選擇性的。

實際的 POST 要求看起來像下列範例:

POST /<tenant-name>.onmicrosoft.com/B2C_1A_ROPC_Auth/oauth2/v2.0/token HTTP/1.1
Host: <tenant-name>.b2clogin.com
Content-Type: application/x-www-form-urlencoded

username=contosouser.outlook.com.ws&password=Passxword1&grant_type=password&scope=openid+bef22d56-552f-4a5b-b90a-1988a7d634ce+offline_access&client_id=bef22d56-552f-4a5b-b90a-1988a7d634ce&response_type=token+id_token

具有離線存取的成功回應看起來像下列範例:

{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik9YQjNhdTNScWhUQWN6R0RWZDM5djNpTmlyTWhqN2wxMjIySnh6TmgwRlki...",
    "token_type": "Bearer",
    "expires_in": "3600",
    "refresh_token": "eyJraWQiOiJacW9pQlp2TW5pYVc2MUY0TnlfR3REVk1EVFBLbUJLb0FUcWQ1ZWFja1hBIiwidmVyIjoiMS4wIiwiemlwIjoiRGVmbGF0ZSIsInNlciI6Ij...",
    "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik9YQjNhdTNScWhUQWN6R0RWZDM5djNpTmlyTWhqN2wxMjIySnh6TmgwRlki..."
}

兌換重新整理令牌

建構 POST 呼叫,就像這裡所示的呼叫一樣。 使用下表中的資訊作為要求本文:

https://<tenant-name>.b2clogin.com/<tenant-name>.onmicrosoft.com/B2C_1A_ROPC_Auth/oauth2/v2.0/token

  • 將 取代 <tenant-name> 為您的 Azure AD B2C 租用戶名稱。
  • 將取代 B2C_1A_ROPC_Auth 為您資源擁有者密碼認證原則的完整名稱。
機碼
grant_type refresh_token
response_type id_token
client_id application-id
resource application-id
refresh_token refresh-token
  • 將取代application-id為來自ROPC_Auth_app註冊的應用程式標識碼。
  • 將取代 refresh-token先前回應中傳回的refresh_token

成功的回應看起來像下列範例:

{
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1jNTdkTzZRR1RWQndhT...",
    "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1jNTdkTzZRR1RWQn...",
    "token_type": "Bearer",
    "not_before": 1533672990,
    "expires_in": 3600,
    "expires_on": 1533676590,
    "resource": "bef2222d56-552f-4a5b-b90a-1988a7d634c3",
    "id_token_expires_in": 3600,
    "profile_info": "eyJ2ZXIiOiIxLjAiLCJ0aWQiOiI1MTZmYzA2NS1mZjM2LTRiOTMtYWE1YS1kNmVlZGE3Y2JhYzgiLCJzdWIiOm51bGwsIm5hbWUiOiJEYXZpZE11IiwicHJlZmVycmVkX3VzZXJuYW1lIjpudWxsLCJpZHAiOiJMb2NhbEFjY291bnQifQ",
    "refresh_token": "eyJraWQiOiJjcGltY29yZV8wOTI1MjAxNSIsInZlciI6IjEuMCIsInppcCI6IkRlZmxhdGUiLCJzZXIiOiIxLjAi...",
    "refresh_token_expires_in": 1209600
}

疑難排解

提供的應用程式未設定為允許 『OAuth』 隱含流程

  • 徵兆 - 您執行 ROPC 流程並取得下列訊息:AADB2C90057: 提供的應用程式未設定為允許 『OAuth』 隱含流程
  • 可能的原因 - 您的應用程式不允許隱含流程。
  • 解決方案:在 Azure AD B2C 中建立 應用程式註冊 時,您必須手動編輯應用程式指令清單,並將 屬性的值 oauth2AllowImplicitFlow 設定為 true。 設定 oauth2AllowImplicitFlow 屬性之後,變更可能需要幾分鐘的時間(通常不超過五分鐘),變更才會生效。

使用原生 SDK 或 App-Auth

Azure AD B2C 符合公用用戶端資源擁有者密碼認證的 OAuth 2.0 標準,且應該與大部分的用戶端 SDK 相容。 如需最新資訊,請參閱原生 App SDK for OAuth 2.0 和 OpenID 連線 實作新式最佳做法

下一步

從 GitHub、 適用於 AndroidiOS 下載已設定與 Azure AD B2C 搭配使用的工作範例。