本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
CloudFront Functions 的 CWT 支援
本節提供 CloudFront Functions 中 CBOR Web Token (CWT) 支援的詳細資訊,可在 CloudFront Edge Locations 啟用安全字符型身分驗證和授權。此支援是以模組形式提供,可在 CloudFront Function 中存取。
若要使用此模組,請使用 JavaScript 執行期 2.0 建立 CloudFront 函數,並在函數程式碼的第一行中包含下列陳述式:
import cf from 'cloudfront';
與此模組相關聯的方法可透過 存取 (其中 * 是萬用字元,代表模組中存在的不同函數):
cf.cwt.*
如需詳細資訊,請參閱適用於 CloudFront Functions 的 JavaScript 執行時期 2.0 功能。
目前,模組僅支援具有 HS256 (HMAC-SHA256) 演算法的 MAC0 結構,字符大小上限為 1KB。
字符結構
本節涵蓋 CWT 模組預期的字符結構。模組預期字符會正確標記和識別 (例如 COSE MAC0)。此外,對於字符的結構,模組遵循 CBOR 物件簽署和加密 (COSE) 【RFC 8152】
( // CWT Tag (Tag value: 61) --- optional ( // COSE MAC0 Structure Tag (Tag value: 17) --- required [ protectedHeaders, unprotectedHeaders, payload, tag, ] ) )
範例 :使用 COSE MAC0 結構的 CWT
61( // CWT tag 17( // COSE_MAC0 tag [ { // Protected Headers 1: 4 // algorithm : HMAC-256-64 }, { // Unprotected Headers 4: h'53796d6d6574726963323536' // kid : Symmetric key id }, { // Payload 1: "https://iss.example.com", // iss 2: "exampleUser", // sub 3: "https://aud.example.com", // aud 4: 1444064944, // exp 5: 1443944944, // nbf 6: 1443944944, // iat }, h'093101ef6d789200' // tag ] ) )
注意
產生字符時,CWT 標籤是選用的。不過,需要 COSE 結構標籤。
validateToken() 方法
函數會使用指定的金鑰解碼和驗證 CWT 字符。如果驗證成功,則會傳回解碼的 CWT 字符。否則,它會擲回錯誤。請注意,此函數不會對宣告集進行驗證。
請求
cf.cwt.validateToken(token, handlerContext{key})
Parameters
- 字符 (必要)
-
用於驗證的編碼字符。這必須是 JavaScript 緩衝區。
- handlerContext (必要)
-
存放 validateToken 呼叫內容的 JavaScript 物件。目前僅支援 金鑰屬性。
- 金鑰 (必要)
-
訊息摘要運算的私密金鑰。可做為字串或 JavaScript 緩衝區提供。
回應
當 validateToken()方法傳回成功驗證的字符時,函數的回應會以下列格式CWTObject顯示 。解碼後,所有宣告金鑰都會以字串表示。
CWTObject { protectedHeaders, unprotectedHeaders, payload }
範例 - 使用作為字符一部分傳送的 kid 驗證字符
此範例示範 CWT 字符驗證,其中會從 標頭擷取 kid。接著 kid 會傳遞至 CloudFront Functions KeyValueStore,以擷取用於驗證權杖的私密金鑰。
import cf from 'cloudfront' const CwtClaims = { iss: 1, aud: 3, exp: 4 } async function handler(event) { try { let request = event.request; let encodedToken = request.headers['x-cwt-token'].value; let kid = request.headers['x-cwt-kid'].value; // Retrieve the secret key from the kvs let secretKey = await cf.kvs().get(kid); // Now you can use the secretKey to decode & validate the token. let tokenBuffer = Buffer.from(encodedToken, 'base64url'); let handlerContext = { key: secretKey, } try { let cwtObj = cf.cwt.validateToken(tokenBuffer, handlerContext); // Check if token is expired const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds if (cwtObj[CwtClaims.exp] && cwtObj[CwtClaims.exp] < currentTime) { return { statusCode: 401, statusDescription: 'Token expired' }; } } catch (error) { return { statusCode: 401, statusDescription: 'Invalid token' }; } } catch (error) { return { statusCode: 402, statusDescription: 'Token processing failed' }; } return request; }
generateToken() 方法
此函數會使用提供的承載和內容設定產生新的 CWT 字符。
請求
cf.cwt.generateToken(generatorContext, payload)
Parameters
- generatorContext (必要)
-
這是 JavaScript 物件,可做為產生字符的內容,並包含下列索引鍵值對:
- cwtTag (選用)
-
此值是布林值,如果
true指定cwtTag應新增 。 - coseTag (必要)
-
指定 COSE 標籤類型。目前僅支援
MAC0。 - 金鑰 (必要)
-
用於運算訊息摘要的私密金鑰。此值可以是字串或 JavaScript
Buffer。
- 承載 (必要)
-
用於編碼的字符承載。承載必須是
CWTObject格式。
回應
傳回包含編碼字符的 JavaScript 緩衝區。
範例 :產生 CWT 字符
import cf from 'cloudfront'; const CwtClaims = { iss: 1, sub: 2, exp: 4 }; const CatClaims = { catu: 401, catnip: 402, catm: 403, catr: 404 }; const Catu = { host: 1, path: 2, ext: 3 }; const CatuMatchTypes = { prefix_match: 1, suffix_match: 2, exact_match: 3 }; const Catr = { renewal_method: 1, next_renewal_time: 2, max_uses: 3 }; async function handler(event) { try { const response = { statusCode: 200, statusDescription: 'OK', headers: {} }; const commonAccessToken = { protected: { 1: "5", }, unprotected: {}, payload: { [CwtClaims.iss]: "cloudfront-documentation", [CwtClaims.sub]: "cwt-support-on-cloudfront-functions", [CwtClaims.exp]: 1740000000, [CatClaims.catu]: { [Catu.host]: { [CatuMatchTypes.suffix_match]: ".cloudfront.net" }, [Catu.path]: { [CatuMatchTypes.prefix_match]: "/media/live-stream/cf-4k/" }, [Catu.ext]: { [CatuMatchTypes.exact_match]: [ ".m3u8", ".ts", ".mpd" ] } }, [CatClaims.catnip]: [ "[IP_ADDRESS]", "[IP_ADDRESS]" ], [CatClaims.catm]: [ "GET", "HEAD" ], [CatClaims.catr]: { [Catr.renewal_method]: "header_renewal", [Catr.next_renewal_time]: 1750000000, [Catr.max_uses]: 5 } } }; if (!request.headers['x-cwt-kid']) { throw new Error('Missing x-cwt-kid header'); } const kid = request.headers['x-cwt-kid'].value; const secretKey = await cf.kvs().get(kid); if (!secretKey) { throw new Error('Secret key not found for provided kid'); } try { const genContext = { cwtTag: true, coseTag: "MAC0", key: secretKey }; const tokenBuffer = cf.cwt.generateToken(commonAccessToken, genContext); response.headers['x-generated-cwt-token'] = { value: tokenBuffer.toString('base64url') }; return response; } catch (tokenError) { return { statusCode: 401, statusDescription: 'Could not generate the token' }; } } catch (error) { return { statusCode: 402, statusDescription: 'Token processing failed' }; } }
範例 :根據某些邏輯重新整理權杖
import cf from 'cloudfront' const CwtClaims = { iss: 1, aud: 3, exp: 4 } async function handler(event) { try { let request = event.request; let encodedToken = request.headers['x-cwt-token'].value; let kid = request.headers['x-cwt-kid'].value; let secretKey = await cf.kvs().get(kid); // Retrieve the secret key from the kvs // Now you can use the secretKey to decode & validate the token. let tokenBuffer = Buffer.from(encodedToken, 'base64url'); let handlerContext = { key: secretKey, } try { let cwtJSON = cf.cwt.validateToken(tokenBuffer, handlerContext); // Check if token is expired const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds if (cwtJSON[CwtClaims.exp] && cwtJSON[CwtClaims.exp] < currentTime) { // We can regnerate the token and add 8 hours to the expiry time cwtJSON[CwtClaims.exp] = Math.floor(Date.now() / 1000) + (8 * 60 * 60); let genContext = { coseTag: "MAC0", key: secretKey } let newTokenBuffer = cf.cwt.generateToken(cwtJSON, genContext); request.headers['x-cwt-regenerated-token'] = newTokenBuffer.toString('base64url'); } } catch (error) { return { statusCode: 401, statusDescription: 'Invalid token' }; } } catch (error) { return { statusCode: 402, statusDescription: 'Token processing failed' }; } return request; }