Ich beabsichtige, die Benutzer meiner Anwendung Dateien direkt in GCS hochladen zu lassen, wofür ich eine PUT request mit einer signierten URL verwende. Mein Code in Python wie folgt aussieht:Signatur stimmt nicht überein mit signierter URL mit GCS
def get(self):
base_url = 'https://storage.googleapis.com/' + self.get_bucket_name()
expiration = utils.unix_time_secs(datetime.now() + timedelta(hours=1))
string_to_sign = ( 'PUT' + "\n" +
'' + "\n" +
'' + "\n" +
str(expiration) + "\n" +
'' + "\n" +
'my-bucket.appspot.com')
signed_string = app_identity.sign_blob(string_to_sign)[1]
signature = base64.b64encode(signed_string)
signature = urllib.quote(signature, safe='')
google_access_id = app_identity.get_service_account_name()
params = '?GoogleAccessId={0}&Expires={1}&Signature={2}'.format(
google_access_id, expiration, signature)
self.template_values['base_url'] = base_url
self.template_values['params'] = params
self.render('testA.html')
Auf der Client-Seite, verwende ich einen XMLHttpRequest die Datei zu GCS senden:
function gCloud (base_url, params, callback) {
var xhr = new XMLHttpRequest();
var file = document.querySelector('#fotos').files[0]
//Here goes an event listener (callback)
url = base_url + '/' + file.name + params
xhr.open("PUT", url, true);
xhr.setRequestHeader("Content-Type", file.type)
xhr.send(file)
}
Das Problem ist, dass, wenn ich diese Anfrage sende ich eine bekommen 403 Unzulässiger Fehler, der besagt, dass die berechnete Signatur nicht mit der von mir angegebenen übereinstimmt. Es ist wahrscheinlich ein dummer Fehler, aber ich kann das nicht zum Laufen bringen. Was könnte das Problem sein?
EDIT:
ich versuchte Google-Cloud-Python, und versucht, diesen Code (das gearbeitet hat):
def get(self):
bucket = storage.Client().get_bucket(self.get_bucket_name())
blob = bucket.blob('Yosemite.jpg')
expiration = utils.unix_time_secs(datetime.now() + timedelta(hours=1))
base_url = blob.generate_signed_url(expiration, "PUT", 'image/jpeg')
self.template_values['base_url'] = base_url
self.render('testA.html')
Das Problem ist jetzt, dass, da 'generate_signed_url' ist ein Verfahren des Blob Klasse es bereits annimmt, ich kenne den eindeutigen Pfad des Objekts, um die URL zu erstellen, wie in Blob = bucket.blob ('Yosemite.jpg'), was ich nicht. Was ist, wenn der Benutzer Space.jpg hochladen möchte? Anstatt my-bucket/Space.jpg zu erstellen, wird Yosemite.jpg überschrieben, also werde ich Yosemite.jpg haben und wenn ich das Bild öffne, wird es tatsächlich Space.jpg sein. Wie kann ich das lösen?
Außerdem, wenn ich Content-Type = 'image-jpeg' nicht in die Funktion 'generate_signed_url' einbeziehe, stimmt die Signatur nicht überein. Was ist, wenn der Benutzer stattdessen ein PNG hochlädt?
Danke für Ihre Antwort. Ich habe versucht, die google_access_id zu umgehen, aber das hat es nicht gelöst. Ich habe versucht, die google-cloud-python-Bibliothek zu verwenden und die Frage entsprechend zu bearbeiten, aber von dem, was ich verstehe, nimmt die Funktion an, dass ich Dinge wie den Namen der Datei oder den Inhaltstyp kenne, bevor ich die URL an den Benutzer übergebe. Was kann ich dagegen tun? –
OH. Sie versuchen, die URL auf der Clientseite zu bearbeiten, um einen Objektnamen anzufügen? Das wird nicht funktionieren.Der Hauptpunkt der signierten URLs besteht darin, Clients daran zu hindern, die Anfrage zu bearbeiten. Wenn Sie möchten, dass der Benutzer den Objektnamen angeben kann, gibt es dafür eine weitere Option: signierte POST-Anforderungsrichtliniendokumente. Siehe https://cloud.google.com/storage/docs/xml-api/post-object#policydocument –
Ich verwende POST für diesen Fall, ich werde PUT für die anderen behalten. Vielen Dank für Ihre Antwort! –