我想使用javascript ajax功能将图像从前端上传到Google存储。我需要服务器生成的一个预签名的url,它将为前端提供身份验证以上传blob。 使用本地计算机时,如何生成预签名的URL。
以前对于aws s3,我会这样做:
pp = s3.generate_presigned_post(
Bucket=settings.S3_BUCKET_NAME,
Key='folder1/' + file_name,
ExpiresIn=20 # seconds
)
为用户生成签名的URL以便仅查看存储在Google存储空间中的文件时,我会这样做:
bucket = settings.CLIENT.bucket(settings.BUCKET_NAME)
blob_name = 'folder/img1.jpg'
blob = bucket.blob(blob_name)
url = blob.generate_signed_url(
version='v4',
expiration=datetime.timedelta(minutes=1),
method='GET')
答案 0 :(得分:2)
花了100美元的Google支持费用和我两个星期的时间终于找到了解决方案。
client = storage.Client() # works on app engine standard without any credentials requirements
但是,如果您想使用generate_signed_url()
功能,则需要服务帐户Json密钥。
每个应用程序引擎标准都有一个默认服务帐户。 (您可以在IAM /服务帐户中找到它)。为该默认sv帐户创建一个密钥,然后以json格式下载密钥('sv_key.json')。将该密钥存储在app.yaml文件旁边的Django项目中。然后执行以下操作:
from google.cloud import storage
CLIENT = storage.Client.from_service_account_json('sv_key.json')
bucket = CLIENT.bucket('bucket_name_1')
blob = bucket.blob('img1.jpg') # name of file to be saved/uploaded to storage
pp = blob.generate_signed_url(
version='v4',
expiration=datetime.timedelta(minutes=1),
method='POST')
这将在您的本地计算机和GAE标准上运行。当您将应用程序部署到GAE时,sv_key.json也将与Django项目一起部署,因此它可以工作。
希望它对您有帮助。
答案 1 :(得分:1)
编辑我的答案,因为我不了解您面临的问题。
就像@Nick Shebanov所说的那样,看问题中的注释线程,有一种可能性可以实现将GAE与flex环境一起使用时要达到的目标。
到目前为止,我一直在尝试使用GAE Standard环境做同样的事情,但是没有运气。此时,我建议在public issue tracker处打开功能请求,以某种方式实现。
答案 2 :(得分:0)
SV_ACCOUNT_KEY
from_service_account_json()
以获取 json 密钥内容而不是 json 文件的路径。这样我们就不必在我们的文件系统(本地、cloudbuild 或 GAE 中)中有一个 json 文件。我们可以随时随地从 SM 获取私钥内容。settings.py
secret = SecretManager()
SV_ACCOUNT_KEY = secret.access_secret_data('SV_ACCOUNT_KEY')
signed_url_mixin.py
import datetime
import json
from django.conf import settings
from google.cloud.storage.client import Client
from google.oauth2 import service_account
class CustomClient(Client):
@classmethod
def from_service_account_json(cls, sv_account_key, *args, **kwargs):
"""
Copying everything from base func (from_service_account_json).
Instead of passing json file for private key, we pass
sv_account_key (json content) to sign a url.
Since its not properly written, we cannot just overwrite a class or a
func, we have to write the entire func.
"""
if "credentials" in kwargs:
raise TypeError("credentials must not be in keyword arguments")
credentials_info = json.loads(sv_account_key)
credentials = service_account.Credentials.from_service_account_info(
credentials_info
)
if cls._SET_PROJECT:
if "project" not in kwargs:
kwargs["project"] = credentials_info.get("project_id")
kwargs["credentials"] = credentials
return cls(*args, **kwargs)
class _SignedUrlMixin:
bucket_name = settings.BUCKET_NAME
CLIENT = CustomClient.from_service_account_json(settings.SV_ACCOUNT_KEY)
exp_min = 4 # expire minutes
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.bucket = self.CLIENT.bucket(self.bucket_name)
def _signed_url(self, file_name, method):
blob = self.bucket.blob(file_name)
signed_url = blob.generate_signed_url(
version='v4',
expiration=datetime.timedelta(minutes=self.exp_min),
method=method
)
return signed_url
class GetSignedUrlMixin(_SignedUrlMixin):
"""
A GET url to view file on CS
"""
def get_signed_url(self, file_name):
"""
:param file_name: name of file to be retrieved from CS.
xyz/f1.pdf
:return: GET signed url
"""
method = 'GET'
return self._signed_url(file_name, method)
class PutSignedUrlMixin(_SignedUrlMixin):
"""
A PUT url to make a put req to upload a file to CS
"""
def put_signed_url(self, file_name):
"""
:file_name: xyz/f1.pdf
"""
method = 'PUT'
return self._signed_url(file_name, method)