在 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 租用戶中註冊應用程式,您可以使用我們新的整合應用程式註冊體驗,或使用舊版應用程式 (舊版) 體驗。 深入了解新體驗。
- 登入 Azure 入口網站。
- 請確定您使用的是包含 Azure AD B2C 租使用者的目錄:
- 在入口網站工具列中選取 [ 目錄 + 訂用帳戶 ] 圖示。
- 在入口 網站設定 |[目錄 + 訂用帳戶 ] 頁面,在 [ 目錄名稱 ] 列表中尋找您的 Azure AD B2C 目錄,然後選取 [ 切換]。
- 在 Azure 入口網站 中,搜尋並選取 [Azure AD B2C]
- 選取 [應用程式註冊],然後選取 [新增註冊]。
- 輸入 應用程式的 [名稱 ]。 例如, ROPC_Auth_app。
- 保留其他值,然後選取 [ 註冊]。
- 記錄應用程式 (用戶端) 識別碼,以供後續步驟使用。
- 在 [管理] 底下,選取 [驗證]。
- 選取 [ 試用新體驗 ](如所示)。
- 在 [進階設定] 和 [啟用下列行動和桌面流程] 區段下,選取 [是] 將應用程式視為公用用戶端。 ROPC 流程需要此設定。
- 選取 [儲存]。
- 在左側功能表中,選取 [ 指令清單 ] 以開啟指令清單編輯器。
- 將 oauth2AllowImplicitFlow 屬性設定為 true:
"oauth2AllowImplicitFlow": true,
- 選取 [儲存]。
建立資源擁有者使用者流程
- 以 Azure AD B2C 租使用者的全域管理員身分登入 Azure 入口網站。
- 如果您有多個租使用者的存取權,請選取頂端功能表中的 設定 圖示,從 [目錄 + 訂用帳戶] 功能表切換至您的 Azure AD B2C 租使用者。
- 在 Azure 入口網站中,搜尋並選取 [Azure AD B2C]。
- 選取 [ 使用者流程],然後選取 [ 新增使用者流程]。
- 選取 [使用資源擁有者密碼認證登入] [ROPC]。
- 在 [版本] 底下,確定已選取 [預覽],然後選取 [建立]。
- 提供使用者流程的名稱,例如 ROPC_Auth。
- 在 [應用程式宣告] 底下,選取 [顯示更多]。
- 選取應用程式所需的應用程式宣告,例如顯示名稱、電子郵件地址和識別提供者。
- 選取確定,然後選取建立。
先決條件
如果您尚未這麼做,請了解開始使用 Active Directory B2C 中的自定義原則入門套件。
建立資源擁有者原則
開啟 TrustFrameworkExtensions.xml 檔案。
如果尚未存在,請新增 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>
在 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>
找出具有 DisplayName 的
Local 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_id 的 DefaultValue 取代為您在必要條件教學課程中建立的 ProxyIdentityExperienceFramework 應用程式的應用程式識別符。 然後將 resource_id的 DefaultValue 取代為您在必要條件教學課程中也建立的 IdentityExperienceFramework 應用程式的應用程式識別碼。
將下列 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>
將 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>
在 Azure AD B2C 租使用者的 [ 自定義原則] 頁面上,選取 [ 上傳原則]。
如果原則存在,請啟用 [覆寫原則],然後流覽至並選取 TrustFrameworkExtensions.xml 檔案。
選取上傳。
建立信賴憑證者檔案
接下來,更新起始您所建立使用者旅程圖的信賴憑證者檔案:
在工作目錄中建立 SignUpOrSignin.xml 檔案的複本,並將它重新命名為 ROPC_Auth.xml。
開啟新檔案,並將 TrustFrameworkPolicy 的 PolicyId 屬性值變更為唯一值。 原則標識碼是您原則的名稱。 例如, B2C_1A_ROPC_Auth。
將 DefaultUserJourney 中 ReferenceId 屬性的值變更為
ResourceOwnerPasswordCredentials
。將 OutputClaims 元素變更為只包含下列宣告:
<OutputClaim ClaimTypeReferenceId="sub" /> <OutputClaim ClaimTypeReferenceId="objectId" /> <OutputClaim ClaimTypeReferenceId="displayName" DefaultValue="" /> <OutputClaim ClaimTypeReferenceId="givenName" DefaultValue="" /> <OutputClaim ClaimTypeReferenceId="surname" DefaultValue="" />
在 Azure AD B2C 租使用者的 [ 自定義原則] 頁面上,選取 [ 上傳原則]。
如果原則存在,請啟用 [覆寫] 原則,然後流覽至並選取 ROPC_Auth.xml 檔案。
選取上傳。
測試 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、 適用於 Android 和 iOS 下載已設定與 Azure AD B2C 搭配使用的工作範例。