简体   繁体   中英

Google Cloud Platform presignURL using Go

Trying to upload a picture to Google Cloud Platform, I always get the same err "<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>GOOG4-RSA-SHA256 20.................951Z" .

I did add a service-account to the bucket with the role Storage Admin and Storage Object Admin as you can see on the pic

在此处输入图像描述

I have generated a Key(for the service account) and downloaded it as.json file, then I generate a presignURL using this code:

// key is the downloaded .json key file from the GCP service-account 
// the return string is the presignedURL 
func getPresignedURL(path, key string) (string, error) {
    sakeyFile := filepath.Join(path, key)

    saKey, err := ioutil.ReadFile(sakeyFile)
    if err != nil {
        log.Fatalln(err)
    }

    cfg, err := google.JWTConfigFromJSON(saKey)
    if err != nil {
        log.Fatalln(err)
    }

    bucket := "mybucket"

    ctx := context.Background()
    client, err := storage.NewClient(ctx)
    if err != nil {
        return "", fmt.Errorf("storage.NewClient: %v", err)
    }
    defer client.Close()

    opts := &storage.SignedURLOptions{
        Scheme: storage.SigningSchemeV4,
        Method: "PUT",
        Headers: []string{
            // "Content-Type:application/octet-stream",
            "Content-Type:multipart/form-data",
        },
        Expires:        time.Now().Add(15 * time.Minute),
        GoogleAccessID: cfg.Email,
        PrivateKey:     cfg.PrivateKey,
    }

    u, err := client.Bucket(bucket).SignedURL("mypic.jpeg", opts)
    if err != nil {
        return "", fmt.Errorf("Bucket(%q).SignedURL: %v", bucket, err)
    }

    return u, nil 
}

The presignedURL looks good, something like this:

https://storage.googleapis.com/djedjepicbucket/mypic.jpeg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=djedje%40picstorage-363707.iam.gserviceaccount.com%2F20220926%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20220926T081951Z&X-Goog-Expires=899&X-Goog Signature=3f330715d7a38ea08f99134a16f464fb............5ad800a7665dfb1440034ab1f5ab045252336&X-Goog-SignedHeaders=content-type%3Bhost

Then I read a file(picture) from disk and upload it using the presignURL

// the uri is the presignedURL
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)
    part, err := writer.CreateFormFile(paramName, filepath.Base(path))
    if err != nil {
        return nil, err
    }
    _, err = io.Copy(part, file)

    for key, val := range params {
        _ = writer.WriteField(key, val)
    }
    err = writer.Close()
    if err != nil {
        return nil, err
    }

    req, err := http.NewRequest("PUT", uri, body)
    req.Header.Set("Content-Type", writer.FormDataContentType())
    return req, err
}

Then I exec the request

// the previous func
request, err := newfileUploadRequest(purl, extraParams, "picture", filepath.Join(path, "download.jpeg"))
if err != nil {
    log.Fatal(err)
}

client := &http.Client{}
resp, err := client.Do(request)
if err != nil {
    log.Fatal(err)
} else {
    body := &bytes.Buffer{}
    _, err := body.ReadFrom(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    resp.Body.Close()
    fmt.Println(resp.StatusCode)
    fmt.Println(resp.Header)
    fmt.Println(body)
}

Unfortunatly, I always get the same error back

403
map[Alt-Svc:[h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"] Content-Length:[884] Content-Type:[application/xml; charset=UTF-8] Date:[Mon, 26 Sep 2022 08:22:19 GMT] Server:[UploadServer] X-Guploader-Uploadid:[ADPyc......................ECL_4W]]
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>GOOG4-RSA-SHA256
20220926T081951Z
20220926/auto/storage/goog4_request
c5f36838af4......................8ffb56329c1eb27f</StringToSign><CanonicalRequest>PUT
/djedjepicbucket/mypic.jpeg
X-Goog-Algorithm=GOOG4-RSA-SHA256&amp;X-Goog-Credential=djedje%40picstorage-363707.iam.gserviceaccount.com%2F20220926%2Fauto%2Fstorage%2Fgoog4_request&amp;X-Goog-Date=20220926T081951Z&amp;X-Goog-Expires=899&amp;X-Goog-SignedHeaders=content-type%3Bhost
content-type:multipart/form-data; boundary=5be13cc........................dd6aef6823
host:storage.googleapis.com

content-type;host
UNSIGNED-PAYLOAD</CanonicalRequest></Error>

Actually I have tryied many other ways as well but I basically always get this(more or less) same err back, Does someone have an Idea what am I forgetting(I am on that for 2 days now...)? Thank you

Found the answer, in the both getPresignedURL() and newfileUploadRequest() func, the Header must be set to "Content-Type:application/octet-stream" , then the pic is uploaded without issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM