Function Compute memungkinkan Anda mengonfigurasi otentikasi tanda tangan untuk pemicu HTTP. Ketika API Gateway menerima permintaan dari operasi API yang menggunakan Function Compute sebagai layanan backend, API Gateway mengotentikasi permintaan tersebut pada nama domain kustom yang telah mengaktifkan fitur otentikasi tanda tangan. Dengan demikian, fungsi Anda tidak perlu lagi mengotentikasi tanda tangan permintaan, sehingga Anda dapat fokus sepenuhnya pada logika bisnis. Topik ini menjelaskan cara mengonfigurasi otentikasi tanda tangan untuk nama domain kustom di Konsol Function Compute.
Sebelum Anda mulai
Prosedur
Masuk ke Konsol Function Compute. Di panel navigasi kiri, pilih .
Di bilah navigasi atas, pilih wilayah tempat nama domain kustom yang ingin Anda kelola berada. Pada halaman Domain Kustom, klik nama domain kustom yang ingin Anda kelola.
Di pojok kanan atas halaman yang muncul, klik Modify. Di bagian Authentication Settings, atur Authentication Method menjadi Signature Authentication, lalu klik Save.

Verifikasi
Tulis dan jalankan kode secara lokal. Gambar berikut menunjukkan struktur direktori kode.

Contoh kode:
signature.go
package sign import ( "bytes" "crypto/hmac" "crypto/sha1" "encoding/base64" "hash" "io" "net/http" "sort" "strings" ) // GetPOPAuthStr ... GetAuthStr mendapatkan string tanda tangan // // @param accessKeyID // @param accessKeySecret // @param req // @return string func GetPOPAuthStr(accessKeyID string, accessKeySecret string, req *http.Request) string { return "acs " + accessKeyID + ":" + GetPOPSignature(accessKeySecret, req) } // GetPOPSignature ... ... // // @param akSecret // @param req // @return string func GetPOPSignature(akSecret string, req *http.Request) string { stringToSign := getStringToSign(req) // fmt.Printf("stringToSign: %s\n", stringToSign) return GetROASignature(stringToSign, akSecret) } // GetROASignature ... ... // // @param stringToSign // @param secret // @return string func GetROASignature(stringToSign string, secret string) string { h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(secret)) io.WriteString(h, stringToSign) signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil)) return signedStr } // getStringToSign ... func getStringToSign(req *http.Request) string { queryParams := make(map[string]string) for k, v := range req.URL.Query() { queryParams[k] = v[0] } // urutkan QueryParams berdasarkan kunci var queryKeys []string for key := range queryParams { queryKeys = append(queryKeys, key) } sort.Strings(queryKeys) tmp := "" for i := 0; i < len(queryKeys); i++ { queryKey := queryKeys[i] v := queryParams[queryKey] if v != "" { tmp = tmp + "&" + queryKey + "=" + v } else { tmp = tmp + "&" + queryKey } } resource := req.URL.EscapedPath() if tmp != "" { tmp = strings.TrimLeft(tmp, "&") resource = resource + "?" + tmp } return getSignedStr(req, resource) } func getSignedStr(req *http.Request, canonicalizedResource string) string { temp := make(map[string]string) for k, v := range req.Header { if strings.HasPrefix(strings.ToLower(k), "x-acs-") { temp[strings.ToLower(k)] = v[0] } } hs := newSorter(temp) // Urutkan temp berdasarkan urutan naik hs.Sort() // Dapatkan canonicalizedOSSHeaders canonicalizedOSSHeaders := "" for i := range hs.Keys { canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n" } // Berikan nilai parameter lainnya // saat menandatangani URL, tanggal adalah masa berlaku date := req.Header.Get("Date") accept := req.Header.Get("Accept") contentType := req.Header.Get("Content-Type") contentMd5 := req.Header.Get("Content-MD5") signStr := req.Method + "\n" + accept + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource return signStr } // Sorter ... type Sorter struct { Keys []string Vals []string } func newSorter(m map[string]string) *Sorter { hs := &Sorter{ Keys: make([]string, 0, len(m)), Vals: make([]string, 0, len(m)), } for k, v := range m { hs.Keys = append(hs.Keys, k) hs.Vals = append(hs.Vals, v) } return hs } // Sort adalah fungsi tambahan untuk fungsi SignHeader. func (hs *Sorter) Sort() { sort.Sort(hs) } // Len adalah fungsi tambahan untuk fungsi SignHeader. func (hs *Sorter) Len() int { return len(hs.Vals) } // Less adalah fungsi tambahan untuk fungsi SignHeader. func (hs *Sorter) Less(i, j int) bool { return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0 } // Swap adalah fungsi tambahan untuk fungsi SignHeader. func (hs *Sorter) Swap(i, j int) { hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i] hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i] }go.mod
module auth.fc.aliyun.com go 1.17main.go
Contoh kode berikut menggunakan variabel lingkungan untuk mendapatkan pasangan AccessKey untuk pemanggilan. Metode ini hanya untuk referensi. Kami menyarankan Anda menggunakan Security Token Service (STS), yang lebih aman. Untuk informasi lebih lanjut, lihat Buat AccessKey dan Kelola kredensial akses.
package main import ( "bytes" "encoding/json" "fmt" "io/ioutil" "net/http" "os" "time" "auth.fc.aliyun.com/sign" ) func main() { // The request URL. Specify the URL as needed. url := "A custom domain name or the endpoint of the HTTP trigger" // In this example, the AccessKey ID and AccessKey secret are stored in environment variables to implement identity authentication. // Make sure that the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET environment variables are configured. // If the project code is leaked, the AccessKey pair may be disclosed, which may compromise the security of resources in your account. ak := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID") sk := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET") // Specify the data that you want to send. data := map[string]interface{}{ "user": "FC 3.0", } jsonData, err := json.Marshal(data) if err != nil { fmt.Printf("Error encoding JSON: %s\n", err) return } // Create a sample request. request, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) if err != nil { fmt.Printf("Error creating request: %s\n", err) return } // Add a request header. request.Header.Set("Content-Type", "application/json") addAuthInfo(request, ak, sk) // Create an HTTP client and send the request. client := &http.Client{} response, err := client.Do(request) if err != nil { fmt.Printf("Error sending request to server: %s\n", err) return } defer response.Body.Close() // Read the content of the response that is returned. body, err := ioutil.ReadAll(response.Body) if err != nil { fmt.Printf("Error reading response body: %s\n", err) return } // Print the content of the response. fmt.Printf("Response Status: %s\n", response.Status) fmt.Printf("Response Body: %s\n", string(body)) } func addAuthInfo(req *http.Request, ak, sk string) { if req.Header.Get("Date") == "" { req.Header.Set("Date", time.Now().UTC().Format(http.TimeFormat)) } // copy from lambda-go-sdk sign-url-request if req.URL.Path == "" { req.URL.Path = "/" } authHeader := sign.GetPOPAuthStr(ak, sk, req) req.Header.Set("Authorization", authHeader) }
Keluaran perintah berikut menunjukkan bahwa respons dari fungsi diperoleh.
Response Status: 200 OK
Response Body: Hello World!FAQ
Mengapa "header HTTP yang diperlukan Date tidak ditentukan" dikembalikan ketika saya menggunakan nama domain kustom untuk mengakses fungsi setelah saya mengaktifkan otentikasi tanda tangan untuk nama domain tersebut?
Pesan tersebut menunjukkan bahwa otentikasi gagal. Berikut adalah kemungkinan penyebabnya:
Permintaan tidak mengandung tanda tangan.
Permintaan mengandung tanda tangan tetapi tidak mengandung header Date.
Mengapa "perbedaan antara waktu permintaan 'Thu, 04 Jan 2024 01:33:13 GMT' dan waktu saat ini 'Thu, 04 Jan 2024 08:34:58 GMT' terlalu besar" dikembalikan ketika saya menggunakan nama domain kustom untuk mengakses fungsi setelah saya mengaktifkan otentikasi tanda tangan untuk nama domain tersebut?
Pesan tersebut menunjukkan bahwa tanda tangan telah kedaluwarsa. Gunakan titik waktu saat ini untuk menandatangani ulang permintaan.
Mengapa "tanda tangan permintaan yang kami hitung tidak cocok dengan tanda tangan yang Anda berikan. Periksa kunci akses dan metode penandatanganan Anda" dikembalikan ketika saya menggunakan nama domain kustom untuk mengakses fungsi setelah saya mengaktifkan otentikasi tanda tangan untuk nama domain tersebut?
Otentikasi gagal karena tanda tangan dalam permintaan tidak sesuai dengan tanda tangan yang dihitung oleh Function Compute.