

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

# 驗證 JSON Web 字符
<a name="amazon-cognito-user-pools-using-tokens-verifying-a-jwt"></a>

JSON Web 字符 JWTs) 可以輕鬆解碼、讀取和修改。修改後的存取權杖會產生權限提升的風險。修改後的 ID 字符會產生模擬的風險。您的應用程式信任您的使用者集區做為權杖發行者，但如果使用者在傳輸中攔截權杖該怎麼辦？ 您必須確保您的應用程式收到與 Amazon Cognito 發行相同的字符。

Amazon Cognito 會發出權杖，這些權杖使用 OpenID Connect (OIDC) 規格的一些完整性和機密性功能。使用者集區字符指出過期時間、發行者和數位簽章等物件的有效性。簽章是 `.`分隔 JWT 的第三個和最後一個區段，是權杖驗證的關鍵元件。惡意使用者可以修改權杖，但如果您的應用程式擷取公有金鑰並比較簽章，則不相符。從 OIDC 身分驗證處理 JWTs 的任何應用程式，都必須在每次登入時執行此驗證操作。

在此頁面上，我們會針對 JWTs 的驗證提出一些一般和特定建議。應用程式開發涵蓋各種程式設計語言和平台。由於 Amazon Cognito 實作的 OIDC 足以接近公有規格，因此您選擇的開發人員環境中任何信譽良好的 JWT 程式庫都可以處理您的驗證需求。

這些步驟描述有關驗證使用者集區 JSON web 權杖 (JWT)。

**Topics**
+ [先決條件](#amazon-cognito-user-pools-using-tokens-prerequisites)
+ [使用 aws-jwt-verify 驗證權杖](#amazon-cognito-user-pools-using-tokens-aws-jwt-verify)
+ [了解和檢查權杖](#amazon-cognito-user-pools-using-tokens-manually-inspect)

## 先決條件
<a name="amazon-cognito-user-pools-using-tokens-prerequisites"></a>

您的程式庫、軟體開發套件或軟體架構可能已處理本節的任務。 AWS SDKs為應用程式中的 Amazon Cognito 使用者集區字符處理和管理提供工具。 AWS Amplify 包含擷取和重新整理 Amazon Cognito 字符的 函數。

如需詳細資訊，請參閱下列頁面。
+ [將 Amazon Cognito 身分驗證和授權與 Web 和行動應用程式整合](cognito-integrate-apps.md)
+ [使用 AWS SDKs的 Amazon Cognito 身分提供者程式碼範例](https://docs.aws.amazon.com/cognito/latest/developerguide/service_code_examples.html)
+ *Amplify 開發人員中心*中的[進階工作流程](https://docs.amplify.aws/lib/auth/advanced/q/platform/js/#retrieve-jwt-tokens)

許多程式庫可用於解碼和驗證 JSON Web 權杖 (JWT)。如果您想手動處理伺服器端 API 處理的權杖，又或者您使用的是其他程式設計語言，那麼這些程式庫就很實用。請參閱[可搭配 JWT 權杖使用的 OpenID Foundation 程式庫清單](http://openid.net/developers/jwt/)。

## 使用 aws-jwt-verify 驗證權杖
<a name="amazon-cognito-user-pools-using-tokens-aws-jwt-verify"></a>

在 Node.js 應用程式中， AWS 建議程式[aws-jwt-verify庫](https://github.com/awslabs/aws-jwt-verify)驗證使用者傳遞至應用程式的字符中的參數。使用 `aws-jwt-verify` 時，您可以使用您要驗證一或多個使用者集區的宣告值填入 `CognitoJwtVerifier`。它可以檢查的一些值包括以下內容。
+ 該存取或 ID 權杖的格式正確或未過期，並具有有效的簽章。
+ 該存取權杖來自[正確的使用者集區和應用程式用戶端](https://github.com/awslabs/aws-jwt-verify#verifying-jwts-from-amazon-cognito)。
+ 該存取權杖宣告包含[正確的 OAuth 2.0 範圍](https://github.com/awslabs/aws-jwt-verify#checking-scope)。
+ 簽署您的存取和 ID 權杖的金鑰[符合來自使用者集區 *JWKS URI* 中的簽署金鑰 `kid`](https://github.com/awslabs/aws-jwt-verify#the-jwks-cache)。

  JWKS URI 包含有關簽署使用者權杖之私有金鑰的公開資訊。您可以在以下位置找到使用者集區的 JWKS URI：`https://cognito-idp.{{<Region>}}.amazonaws.com/{{<userPoolId>}}/.well-known/jwks.json`。

如需可在 Node.js 應用程式或 AWS Lambda 授權方中使用的詳細資訊和範例程式碼，請參閱 GitHub 上的 [https://github.com/awslabs/aws-jwt-verify](https://github.com/awslabs/aws-jwt-verify)。

## 了解和檢查權杖
<a name="amazon-cognito-user-pools-using-tokens-manually-inspect"></a>

在將權杖檢查與應用程式整合之前，請考慮 Amazon Cognito 如何組合 JWT。從使用者集區擷取範例權杖。對它們進行詳細解碼和檢查以了解它們的特徵，並確定您要驗證的內容和時間。例如，您可能想在一種情況下檢查群組成員資格，而在另一種情況下檢查範圍。

以下區段說明在準備應用程式時，手動檢查 Amazon Cognito JWT 的程序。

### 確認 JWT 的結構。
<a name="amazon-cognito-user-pools-using-tokens-step-1"></a>

JSON Web 權杖 (JWT) 包含三個區段，它們之間有一個 `.` (點號) 分隔符號。

**標頭**  
Amazon Cognito 用來簽署權杖的金鑰 ID (`kid`) 和 RSA 演算法 (`alg`)。Amazon Cognito 使用 `RS256` 的 `alg` 簽署權杖。`kid` 是使用者集區所持有之 2048 位元 RSA 私有簽署金鑰的截斷參考。

**酬載**  
權杖宣告。在 ID 權杖中，宣告包括使用者屬性和有關使用者集區 (`iss`) 和應用程式用戶端 (`aud`) 的資訊。在存取權杖中，承載包括範圍、群組成員資格、您的使用者集區為 `iss`，以及您的應用程式用戶端為 `client_id`。

**簽章**  
簽章無法像標頭和承載一樣分解 base64url。它是從您可在 JWKS URI 中觀察到的簽署金鑰和參數衍生出來的 RSA256 識別符。

標頭和承載是 base64url 編碼的 JSON。您可以透過解碼為起始字元 `{` 的開頭字元 `eyJ` 以識別它們。如果您的使用者向您的應用程式提供 base64url 編碼的 JWT，且其格式不是 `[JSON Header].[JSON Payload].[Signature]`，則它不是有效的 Amazon Cognito 字符，您可以將其捨棄。

下列範例應用程式會使用 驗證使用者集區字符`aws-jwt-verify`。

```
// cognito-verify.js
// Usage example: node cognito-verify.js eyJra789ghiEXAMPLE

const { CognitoJwtVerifier } = require('aws-jwt-verify');

// Replace with your Amazon Cognito user pool ID
const userPoolId = '{{us-west-2_EXAMPLE}}';

async function verifyJWT(token) {
  try {
    const verifier = CognitoJwtVerifier.create({
      userPoolId,
      tokenUse: '{{access}}', // or 'id' for ID tokens
      clientId: '{{1example23456789}}', // Optional, only if you need to verify the token audience
    });

    const payload = await verifier.verify(token);
    console.log('Decoded JWT:', payload);
  } catch (err) {
    console.error('Error verifying JWT:', err);
  }
}

// Example usage
if (process.argv.length < 3) {
  console.error('Please provide a JWT token as an argument.');
  process.exit(1);
}

const MyToken = process.argv[2];
verifyJWT(MyToken);
```

### 驗證 JWT
<a name="amazon-cognito-user-pools-using-tokens-step-2"></a>

JWT 簽章是標頭和酬載的雜湊組合。Amazon Cognito 會為每個使用者集區產生兩組 RSA 加密金鑰對。一個私有金鑰簽署存取權杖，另一個簽署 ID 權杖。

**驗證 JWT 權杖的簽章**

1. 解碼 ID 權杖。

   OpenID Foundation 也會[提供可搭配 JWT 權杖使用的程式庫清單](http://openid.net/developers/jwt/)。

   您也可以使用 AWS Lambda 解碼使用者集區 JWTs。如需詳細資訊，請參閱[使用 解碼和驗證 Amazon Cognito JWT 權杖 AWS Lambda](https://github.com/awslabs/aws-support-tools/tree/master/Cognito/decode-verify-jwt)。

1. 比較本機金鑰 ID (`kid`) 與公有 `kid`。

   1. 下載並存放對應至您的使用者集區的公開 JSON Web Key (JWK)。JSON Web Key Set (JWKS) 中會提供這個金鑰。針對您的環境建構以下 `jwks_uri` URI 即可找到它：

      ```
      https://cognito-idp.{{<Region>}}.amazonaws.com/{{<userPoolId>}}/.well-known/jwks.json
      ```

      如需 JWK 和 JWK Set 的詳細資訊，請參閱 [JSON Web Key (JWK)](https://tools.ietf.org/html/rfc7517)。
**注意**  
Amazon Cognito 可能會輪換使用者集區中的簽署金鑰。最佳做法是在應用程式中快取公有金鑰，使用 `kid` 做為快取金鑰，並定期重新整理快取。將應用程式所收到權杖中的 `kid` 與您的快取進行比較。  
如果您收到的權杖具有正確的發行者但 `kid` 不同，則 Amazon Cognito 可能已輪換簽署金鑰。從您的使用者集區 `jwks_uri` 端點重新整理快取。

      這是範本 `jwks.json` 檔案：

      ```
      {
      	"keys": [{
      		"kid": "1234example=",
      		"alg": "RS256",
      		"kty": "RSA",
      		"e": "AQAB",
      		"n": "1234567890",
      		"use": "sig"
      	}, {
      		"kid": "5678example=",
      		"alg": "RS256",
      		"kty": "RSA",
      		"e": "AQAB",
      		"n": "987654321",
      		"use": "sig"
      	}]
      }
      ```  
**金鑰 ID (`kid`)**  
`kid` 是指出在保護權杖之 JSON Web Signature (JWS) 安全時所使用金鑰的提示。  
**演算法 (`alg`)**  
`alg` 標頭參數代表用來保護 ID 權杖安全的加密演算法。使用者集區是使用 RS256 演算法，即採用 SHA-256 的 RSA 簽章。如需 RSA 的詳細資訊，請參閱 [RSA 加密法](https://tools.ietf.org/html/rfc3447)。  
**金鑰類型 (`kty`)**  
`kty` 參數會識別搭配金鑰 (本範例中的金鑰為 "RSA") 的加密演算法系列。  
**RSA 指數 (`e`)**  
這個 `e` 參數包含 RSA 公開金鑰的指數值。它以 Base64urlUInt 編碼值表示。  
**RSA 模數 (`n`)**  
這個 `n` 參數包含 RSA 公開金鑰的模數值。它以 Base64urlUInt 編碼值表示。  
**用途 (`use`)**  
這個 `use` 參數描述公開金鑰的用途。在這個範例中，`use` 值 `sig` 代表簽章。

   1. 搜尋符合您的 JWT 中 `kid` 之 `kid` 的公有 JSON Web 金鑰。

### 驗證宣告
<a name="amazon-cognito-user-pools-using-tokens-step-3"></a>

**驗證 JWT 宣告**

1. 利用下列其中一種方法確認權杖尚未過期。

   1. 解碼權杖，並將 `exp` 宣告與目前時間進行比較。

   1. 如果您的存取權杖包含 `aws.cognito.signin.user.admin` 宣告，請傳送請求至 API (如 [getUser](https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_GetUser.html))。如果您的權杖已過期，那麼您[使用存取權杖進行授權](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pools-API-operations.html#user-pool-apis-auth-unauth)的 API 請求將會傳回錯誤。

   1. 在對 [userInfo 端點](userinfo-endpoint.md) 提出的請求中顯示存取權杖。如果您的權杖已過期，您的請求將會傳回錯誤。

1. 在 ID 權杖中的 `aud` 宣告和在存取權杖中的 `client_id` 宣告應符合在 Amazon Cognito 使用者集區建立的應用程式用戶端 ID。

1. 發行者 (`iss`) 宣告應該符合您的使用者集區。例如，在 `us-east-1` 區域中建立的使用者集區會有以下 `iss` 值：

   `https://cognito-idp.us-east-1.amazonaws.com/{{<userpoolID>}}`.

1. 檢查 `token_use`宣告。
   + 如果您在 Web API 操作中只接受存取權杖，其值必須是 `access`。
   + 如果您只使用 ID 權杖，其值必須是 `id`。
   + 如果是同時使用 ID 權杖和存取權杖，`token_use` 宣告必須是 `id` 或 `access`。

您現在可以信任權杖內部的宣告。