簡體   English   中英

S3、簽名 URL 和緩存

[英]S3, Signed-URLs and Caching

我正在使用 knox nodejs-library 在我的 webapp (nodejs) 上生成簽名的 url。 但是問題出現了,對於每個請求,我需要為當前用戶重新生成一個唯一的 GET 簽名 url,從而使瀏覽器的緩存控制無法進行。

我搜索了 web 但沒有成功,因為瀏覽器似乎使用完整的 url 作為緩存鍵,所以我真的很好奇在給定的情況下(nodejs,knox 庫)如何解決問題並使用緩存控制,同時仍然能夠為每個請求生成簽名 url,因為我需要驗證用戶的訪問權限。

我不敢相信沒有解決方案。

我正在使用 Java AmazonS3 客戶端,但過程應該是相同的。

有一種策略可用於處理這種情況。

您可以使用固定日期時間作為到期日期。 我把這個日期定為明天中午 12 點

現在,每次生成 url 時,它在當天的 00:00 之前都是相同的。 這樣可以在某種程度上使用瀏覽器緩存。

如果您將 CloudFront 與 S3 一起使用,您可以使用自定義策略,如果您將每個 url 限制為用戶的 IP 和合理長的超時,這意味着當他們再次請求相同的內容時,他們將獲得相同的 URL,因此他們的瀏覽器可以緩存內容,但 URL 不適用於其他人(在不同的 IP 上)。

(參見: http : //docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html

擴展@semir-deljić 答案。

每次我們調用getSignedUrl函數時,它都會生成新的 URL。 即使存在Cache Control標頭,這也會導致圖像不被緩存。

因此,我們使用計時庫來凍結時間。 現在當函數被調用時,它認為時間還沒有過去,它返回相同的 URL。

const moment = require('moment');
const tk = require("timekeeper");

function url4download(awsPath, awsKey) {

  function getFrozenDate() {
    return moment().startOf('week').toDate();
  }

  // Paramters for getSignedUrl function
  const params = {
    // Ref: https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html
    // Ref: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
    Bucket: awsBucket,
    Key: `${awsPath}/${awsKey}`,
    // 604800 == 7 days
    ResponseCacheControl: `public, max-age=604800, immutable`,
    Expires: 604800, // 7 days is max
  };

  const url = tk.withFreeze(getFrozenDate(), () => {
    return S3.getSignedUrl('getObject', params);
  });
  return url;
}

注意:使用moment().toDate() ,因為計時器需要一個本地日期對象。

即使是使用knox庫的問題,我的回答也使用 aws 官方庫。

// This is how the AWS & S3 is initiliased.
const AWS = require('aws-sdk');

const S3 = new AWS.S3({
  accessKeyId: awsAccessId,
  secretAccessKey: awsSecretKey,
  region: 'ap-south-1',
  apiVersion: '2006-03-01',
  signatureVersion: 'v4',
});

靈感來源: https : //advancedweb.hu/cacheable-s3-signed-urls/

在計算已簽名的 URL 時,您可以將 'signingDate' 設置為過去的固定時刻,例如昨天早上,然后從該時刻開始計算到期時間。 不要忘記使用 UTC 並考慮時區。

import { S3Client, GetObjectCommand, GetObjectCommandInput } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

let signingDate = new Date();
signingDate.setUTCHours(0, 0, 0, 0);
signingDate.setUTCDate(signingDate.getUTCDate() - 1);

let params: GetObjectCommandInput = {
    Bucket: BUCKET_NAME,
    Key: filename
};
const command = new GetObjectCommand(params);
const url = await getSignedUrl(s3Client,
    command, {
        expiresIn: 3 * 3600 * 24, // 1 day until today + 1 expiration + 1 days for timezones
        signableHeaders: new Set < string > (),
        signingDate: signingDate
    });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM