当我签署谷歌云存储网址时,该网址会在几天后返回
SignatureDoesNotMatch
,但只是有时。
基于 Cloud Storage 下载 URL 在三天后失败,可能是由于 Content-Type?,我认为添加 content_type 可以修复它。
这是我的代码:
credentials, _project_id = google.auth.default()
storage_client = storage.Client()
bucket = storage_client.bucket(UPLOAD_BUCKET)
blob = bucket.blob(blob_name)
signing_credentials = impersonated_credentials.Credentials(
source_credentials=credentials,
target_principal=SERVICE_ACCOUNT_EMAIL,
target_scopes = 'https://www.googleapis.com/auth/devstorage.read_only',
lifetime=2 )
url = blob.generate_signed_url(
version="v4",
expiration=timedelta(seconds=MEDIA_EXPIRATION), # 7 days is max
method="GET",
content_type=blob.content_type, # I think this is setting content_type=None, since blob.reload() is necessary to get a non-None value.
credentials=signing_credentials
)
# note: I'm not sure if I could have just used credentials=credentials instead of the impersonated_credentials.
一个小旁注:blob.content_type 实际上返回 None。您必须执行
blob.reload()
才能获取 content_type。但是添加 content_type 会导致下载失败,因为浏览器在请求图像时不会在标头中包含 content_type。
如所示,Google Cloud Function 中的 getSignedURL() 生成的链接可以运行几天,然后在链接到 https://github.com/googleapis/nodejs-storage/issues/244 的评论中返回“SignatureDoesNotMatch”,一个潜在的原因是 使用默认的 App Engine 服务帐户来签署云存储 blob 。默认服务帐户的密钥经常会轮换,当这种情况发生时,您的所有签名都会被破坏。
为了解决这个问题,我创建了一个具有Storage Object Viewer
权限的专用服务帐户,下载了 json 密钥,将其放入我的项目中并直接使用。
SERVICE_ACCOUNT_FILE = 'my-service-account-json-key.json'
path = os.path.join(os.path.dirname(__file__), SERVICE_ACCOUNT_FILE)
SCOPES = ['https://www.googleapis.com/auth/devstorage.read_only']
credentials2 = service_account.Credentials.from_service_account_file(
path, scopes=SCOPES)
url = blob.generate_signed_url(
version="v4",
expiration=timedelta(seconds=MEDIA_EXPIRATION), # 7 days is max
method="GET",
credentials=credentials2
)
在我的应用中,安全性要求并不高。将资产放入公共桶中是合理的。服务帐户的权限非常有限,只有Storage Object Viewer
,所以我不担心将私钥包含在我的存储库中。最好将其放入 firestore 或 github Secret 中。这个特殊问题是邪恶的,因为如果您幸运地掌握了默认 appengine 服务帐户密钥轮换的时间,您的应用程序可以运行数周或数月。如果长期测试发现其他问题,我将更新此内容或删除它。
很多其他答案都谈到过期时间。如果 url 过期,您会收到过期错误,而不是
SignatureDoesNotMatch
。过期时间从来都不是我的问题,除了它不太可能以更长的时间达到默认服务帐户密钥轮换。