

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 自訂身分驗證挑戰 Lambda 觸發程序
<a name="user-pool-lambda-challenge"></a>

當您為 Amazon Cognito 使用者集區建置身分驗證流程時，您可能會發現您想要將身分驗證模型延伸到內建流程之外。自訂挑戰觸發程序的一個常見使用案例是實作使用者名稱、密碼和多重要素驗證 (MFA) 以外的其他安全檢查。自訂挑戰是您可以使用 Lambda 支援的程式設計語言產生的任何問題和回應。例如，您可能想要要求使用者先解決 CAPTCHA 或回答安全問題，才能進行身分驗證。另一個潛在需求是整合特殊身分驗證因素或裝置。或者，您可能已經開發了使用硬體安全金鑰或生物識別裝置對使用者進行身分驗證的軟體。自訂挑戰的身分驗證成功定義是 Lambda 函數接受的正確答案：固定字串，例如外部 API 的滿意回應。

您可以使用自訂挑戰開始身分驗證，並完全控制身分驗證程序，或者您可以在應用程式收到自訂挑戰之前執行使用者名稱密碼身分驗證。

自訂身分驗證挑戰 Lambda 觸發條件：

**[定義](user-pool-lambda-define-auth-challenge.md)**  
啟動挑戰序列。決定您是否要啟動新的挑戰、將身分驗證標記為完成，或停止身分驗證嘗試。

**[建立](user-pool-lambda-create-auth-challenge.md)**  
向應用程式發出使用者必須回答的問題。此函數可能會顯示安全問題或 CAPTCHA 的連結，您的應用程式應顯示給您的使用者。

**[驗證](user-pool-lambda-verify-auth-challenge-response.md)**  
知道預期的答案，並將其與應用程式在挑戰回應中提供的答案進行比較。函數可能會呼叫 CAPTCHA 服務的 API，以擷取使用者嘗試解決方案的預期結果。

這三個 Lambda 函數會串連在一起，以呈現完全由您控制且屬於您自己的設計的身分驗證機制。由於自訂身分驗證需要用戶端和 Lambda 函數中的應用程式邏輯，因此您無法在受管登入中處理自訂身分驗證。此身分驗證系統需要額外的開發人員工作。您的應用程式必須使用使用者集區 API 執行身分驗證流程，並使用在自訂身分驗證挑戰中心轉譯問題的自訂建立登入介面來處理產生的挑戰。

![挑戰 Lambda 觸發程序](http://docs.aws.amazon.com/zh_tw/cognito/latest/developerguide/images/lambda-challenges.png)


如需實作自訂身分驗證的詳細資訊，請參閱 [自訂身分驗證流程與挑戰](amazon-cognito-user-pools-authentication-flow-methods.md#Custom-authentication-flow-and-challenges)

API 操作 [InitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html) 或 [AdminInitiateAuth](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminInitiateAuth.html) 與 [RespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html) 或 [AdminRespondToAuthChallenge](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminRespondToAuthChallenge.html) 之間的身分驗證。在此流程中，使用者身分驗證會透過回答連續挑戰，直到驗證失敗或者使用者發出字符為止。挑戰回應可能是新的挑戰。在這種情況下，您的應用程式會視需要回應新挑戰的次數。當定義身分驗證挑戰函數分析目前為止的結果、判斷所有挑戰都已回答，並傳回 時，就會發生身分驗證成功`IssueTokens`。

**Topics**
+ [自訂挑戰流程中的 SRP 身分驗證](#user-pool-lambda-challenge-srp-authentication)
+ [定義驗證挑戰 Lambda 觸發程序](user-pool-lambda-define-auth-challenge.md)
+ [建立驗證挑戰 Lambda 觸發程序](user-pool-lambda-create-auth-challenge.md)
+ [確認驗證挑戰回應 Lambda 觸發程序](user-pool-lambda-verify-auth-challenge-response.md)

## 自訂挑戰流程中的 SRP 身分驗證
<a name="user-pool-lambda-challenge-srp-authentication"></a>

您可以讓 Amazon Cognito 在發出自訂挑戰之前驗證使用者密碼。當您在自訂挑戰流程中執行 SRP 驗證時，會執行[請求率配額](quotas.md#category_operations.title)驗證類別中關聯的任何 Lambda 觸發程序。下列為此程序的概觀：

1. 您的應用程式使用 `AuthParameters` 對應透過呼叫 `InitiateAuth` 或 `AdminInitiateAuth` 啟動登入。參數必須包含 `CHALLENGE_NAME: SRP_A,` 以及 `SRP_A` 和 `USERNAME` 的值。

1. Amazon Cognito 以包含 `challengeName: SRP_A` 和 `challengeResult: true` 初始工作階段，叫用您的定義驗證挑戰 Lambda 觸發程序。

1. 收到這些輸入後，您的 Lambda 函數會以 `challengeName: PASSWORD_VERIFIER`、`issueTokens: false`、`failAuthentication: false` 回應。

1. 如果密碼驗證成功，Amazon Cognito 會再次以包含 `challengeName: PASSWORD_VERIFIER` 和 `challengeResult: true` 的新工作階段，叫用您的 Lambda 函數。

1. 您的 Lambda 函數會以 `challengeName: CUSTOM_CHALLENGE`、`issueTokens: false` 和 `failAuthentication: false` 回應，啟動您的自訂挑戰。如果您不想透過密碼驗證開始自訂驗證流程，您可以使用 `AuthParameters` 對應 (包括 `CHALLENGE_NAME: CUSTOM_CHALLENGE`) 啟動登入。

1. 除非已回答所有挑戰，否則挑戰迴圈會不斷重複。

以下是在具有 SRP 流程的自訂身分驗證之前啟動`InitiateAuth`請求的範例。

```
{
    "AuthFlow": "CUSTOM_AUTH",
    "ClientId": "1example23456789",
    "AuthParameters": {
        "CHALLENGE_NAME": "SRP_A",
        "USERNAME": "testuser",
        "SRP_A": "[SRP_A]",
        "SECRET_HASH": "[secret hash]"
    }
}
```

### 自訂身分驗證 SRP 流程中的密碼重設
<a name="user-pool-lambda-challenge-force-password-change"></a>

當使用者處於 `FORCE_CHANGE_PASSWORD` 狀態時，您的自訂身分驗證流程必須整合密碼變更步驟，同時保持身分驗證挑戰的完整性。Amazon Cognito [會在挑戰期間調用您的定義身分驗證](user-pool-lambda-define-auth-challenge.md)`NEW_PASSWORD_REQUIRED`挑戰 Lambda 觸發條件。在此案例中，使用自訂挑戰流程和 SRP 身分驗證登入的使用者如果處於密碼重設狀態，則可以設定新密碼。

當使用者處於 `RESET_REQUIRED`或 `FORCE_CHANGE_PASSWORD` 狀態時，他們必須使用 [回應](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_RespondToAuthChallenge.html#API_RespondToAuthChallenge_RequestParameters)`NEW_PASSWORD_REQUIRED`挑戰`NEW_PASSWORD`。在搭配 SRP 的自訂身分驗證中，Amazon Cognito 會在使用者完成 SRP `NEW_PASSWORD_REQUIRED`挑戰後傳回`PASSWORD_VERIFIER`挑戰。您的定義身分驗證挑戰觸發會在`session`陣列中接收兩個挑戰結果，並在使用者成功變更密碼後繼續進行其他自訂挑戰。

您的定義驗證挑戰 Lambda 觸發程序必須透過 SRP 身分驗證、密碼重設和後續自訂挑戰來管理挑戰序列。觸發會在 `session` 參數中收到一系列已完成的挑戰，包括 `PASSWORD_VERIFIER`和 `NEW_PASSWORD_REQUIRED`結果。如需實作範例，請參閱 [定義驗證挑戰範例](user-pool-lambda-define-auth-challenge.md#aws-lambda-triggers-define-auth-challenge-example)。

#### 身分驗證流程步驟
<a name="user-pool-lambda-challenge-password-flow-steps"></a>

對於需要在自訂挑戰之前驗證其密碼的使用者，程序遵循下列步驟：

1. 您的應用程式使用 `AuthParameters` 對應透過呼叫 `InitiateAuth` 或 `AdminInitiateAuth` 啟動登入。參數必須包含 `CHALLENGE_NAME: SRP_A`、 和 `SRP_A`和 的值`USERNAME`。

1. Amazon Cognito 以包含 `challengeName: SRP_A` 和 `challengeResult: true` 初始工作階段，叫用您的定義驗證挑戰 Lambda 觸發程序。

1. 收到這些輸入後，您的 Lambda 函數會以 `challengeName: PASSWORD_VERIFIER`、`issueTokens: false`、`failAuthentication: false` 回應。

1. 如果密碼驗證成功，會發生以下兩種情況之一：  
**對於處於正常狀態的使用者：**  
Amazon Cognito 會使用包含 `challengeName: PASSWORD_VERIFIER`和 的新工作階段再次調用 Lambda 函數`challengeResult: true`。  
您的 Lambda 函數會以 `challengeName: CUSTOM_CHALLENGE`、`issueTokens: false` 和 `failAuthentication: false` 回應，啟動您的自訂挑戰。  
**對於處於 `RESET_REQUIRED`或 `FORCE_CHANGE_PASSWORD` 狀態的使用者：**  
Amazon Cognito 會使用包含 `challengeName: PASSWORD_VERIFIER`和 的工作階段來叫用 Lambda 函數`challengeResult: true`。  
您的 Lambda 函數應以 `challengeName: NEW_PASSWORD_REQUIRED`、`issueTokens: false` 和 `failAuthentication: false` 回應。  
成功變更密碼後，Amazon Cognito 會使用包含 `PASSWORD_VERIFIER`和 `NEW_PASSWORD_REQUIRED`結果的工作階段來叫用 Lambda 函數。  
您的 Lambda 函數會以 `challengeName: CUSTOM_CHALLENGE`、`issueTokens: false` 和 `failAuthentication: false` 回應，啟動您的自訂挑戰。

1. 除非已回答所有挑戰，否則挑戰迴圈會不斷重複。

如果您不想透過密碼驗證開始自訂驗證流程，您可以使用 `AuthParameters` 對應 (包括 `CHALLENGE_NAME: CUSTOM_CHALLENGE`) 啟動登入。

#### 工作階段管理
<a name="user-pool-lambda-challenge-session-management"></a>

身分驗證流程會透過一系列工作階段 IDs和挑戰結果來維持工作階段連續性。每個挑戰回應都會產生新的工作階段 ID，以防止工作階段重複使用錯誤，這對多重驗證流程特別重要。

挑戰結果會依時間順序儲存在 Lambda 觸發器收到的工作階段陣列中。對於處於 `FORCE_CHANGE_PASSWORD` 狀態的使用者，工作階段陣列包含：

1. `session[0]` - 初始`SRP_A`挑戰

1. `session[1]` - `PASSWORD_VERIFIER`結果

1. `session[2]` - `NEW_PASSWORD_REQUIRED`結果

1. 後續元素 - 其他自訂挑戰的結果

#### 範例身分驗證流程
<a name="user-pool-lambda-challenge-example-flow"></a>

下列範例示範`FORCE_CHANGE_PASSWORD`狀態為 必須同時完成密碼變更和自訂 CAPTCHA 挑戰之使用者的完整自訂身分驗證流程。

1. **InitiateAuth 請求**

   ```
   {
       "AuthFlow": "CUSTOM_AUTH",
       "ClientId": "{{1example23456789}}",
       "AuthParameters": {
           "CHALLENGE_NAME": "SRP_A",
           "USERNAME": "{{testuser}}",
           "SRP_A": "{{[SRP_A]}}"
       }
   }
   ```

1. **InitiateAuth 回應**

   ```
   {
       "ChallengeName": "PASSWORD_VERIFIER",
       "ChallengeParameters": {
           "USER_ID_FOR_SRP": "{{testuser}}"
       },
       "Session": "{{[session_id_1]}}"
   }
   ```

1. **使用 的 RespondToAuthChallenge 請求 `PASSWORD_VERIFIER`**

   ```
   {
       "ChallengeName": "PASSWORD_VERIFIER",
       "ClientId": "{{1example23456789}}",
       "ChallengeResponses": {
           "PASSWORD_CLAIM_SIGNATURE": "{{[claim_signature]}}",
           "PASSWORD_CLAIM_SECRET_BLOCK": "{{[secret_block]}}",
           "TIMESTAMP": "{{[timestamp]}}",
           "USERNAME": "{{testuser}}"
       },
       "Session": "{{[session_id_1]}}"
   }
   ```

1. **RespondToAuthChallenge 回應與`NEW_PASSWORD_REQUIRED`挑戰**

   ```
   {
       "ChallengeName": "NEW_PASSWORD_REQUIRED",
       "ChallengeParameters": {},
       "Session": "{{[session_id_2]}}"
   }
   ```

1. **使用 的 RespondToAuthChallenge 請求 `NEW_PASSWORD_REQUIRED`**

   ```
   {
       "ChallengeName": "NEW_PASSWORD_REQUIRED",
       "ClientId": "{{1example23456789}}",
       "ChallengeResponses": {
           "NEW_PASSWORD": "{{[password]}}",
           "USERNAME": "{{testuser}}"
       },
       "Session": "{{[session_id_2]}}"
   }
   ```

1. **使用 CAPTCHA 自訂挑戰的 RespondToAuthChallenge 回應**

   ```
   {
       "ChallengeName": "CUSTOM_CHALLENGE",
       "ChallengeParameters": {
           "captchaUrl": "url/123.jpg"
       },
       "Session": "{{[session_id_3]}}"
   }
   ```

1. **RespondToAuthChallenge 請求與 CAPTCHA 自訂挑戰的答案**

   ```
   {
       "ChallengeName": "CUSTOM_CHALLENGE",
       "ClientId": "{{1example23456789}}",
       "ChallengeResponses": {
           "ANSWER": "{{123}}",
           "USERNAME": "{{testuser}}"
       },
       "Session": "{{[session_id_3]}}"
   }
   ```

**6. 最終成功回應**

```
{
    "AuthenticationResult": {
        "AccessToken": "{{eyJra456defEXAMPLE}}",
        "ExpiresIn": 3600,
        "IdToken": "{{eyJra789ghiEXAMPLE}}",
        "RefreshToken": "{{eyJjd123abcEXAMPLE}}",
        "TokenType": "Bearer"
    },
    "ChallengeParameters": {}
}
```