tencent cloud

All product documents
API Gateway
Last updated: 2023-12-22 10:06:16
Go
Last updated: 2023-12-22 10:06:16

Overview

This document describes how to manage access to your APIs through application authentication in Go.

Directions

1. In the API Gateway console, create an API and select the authentication type as App authentication. To learn more about the authentication types, please find the documentation for different types of backends in Creating API - Overview.
2. Release the service where the API resides to an environment. See Service Release and Deactivation.
3. Create an application on the Application page in the console.
4. Select the created application in the application list, click Bind API, select the service and API, and click Submit to bind the application to the API.
5. Generate signing information in Go by referring to the Sample Code.

Environmental Dependencies

API Gateway provides sample codes with the request body in JSON format and form-data format. Please select as needed.

Notes

For more information on operations such as application lifecycle management, authorizing an app to access the API, and binding an app to an API, please see Application Management.
For the application signature generation process, please see Application Authentication.

Sample Code

Sample code with the request body in JSON format

package main

import (
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"sort"
"strings"
"time"
)

func main() {
// Application's `ApiAppKey`
const ApiAppKey = "Your ApiAppKey"
// Application's `ApiAppSecret`
const ApiAppSecret = "Your ApiAppSecret"

const Url = "http://service-xxx-xxx.gz.apigw.tencentcs.com/"

const GmtFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
const HTTPMethod = "GET"
const Accept = "application/json"
const ContentType = "application/json"

// Parse `Host` and `Path` according to `Url`
u, err := url.Parse(Url)
if err != nil {
log.Fatal(err)
}
Host:= u.Hostname()
Path:= u.Path
Query := u.RawQuery

// Environment information is not included in the signature path
if strings.HasPrefix(Path, "/release") {
Path = strings.TrimPrefix(Path, "/release")
}else if strings.HasPrefix(Path, "/test") {
Path = strings.TrimPrefix(Path, "/test")
}else if strings.HasPrefix(Path, "/prepub") {
Path = strings.TrimPrefix(Path, "/prepub")
}

if Path == "" {
Path = "/"
}

// Splice query parameters. The query parameters need to be sorted in lexicographical order.
if len(Query) > 0 {
args, _ := url.ParseQuery(Query)

var keys []string
for k := range args {
keys = append(keys, k)
}
sort.Strings(keys)

sortQuery := ""
for _, k := range keys {
if args[k][0] != "" {
sortQuery = sortQuery + "&" + k + "=" + args[k][0]
} else {
sortQuery = sortQuery + "&" + k
}
}
sortQuery = strings.TrimPrefix(sortQuery, "&")

Path = Path + "?" + sortQuery
}

// Get the current UTC time
xDate := time.Now().UTC().Format(GmtFormat)
ContentMD5 := ""
bodyStr := `{"arg1":"a","arg2":"b"}`
if HTTPMethod == "POST" {
h := md5.New()
h.Write([]byte(bodyStr))
md5Str := hex.EncodeToString(h.Sum(nil))
ContentMD5 = base64.StdEncoding.EncodeToString([]byte(md5Str))
}

// Construct the signature
signingStr := fmt.Sprintf("x-date: %s\n%s\n%s\n%s\n%s\n%s", xDate, HTTPMethod, Accept, ContentType,
ContentMD5, Path)
mac := hmac.New(sha1.New, []byte(ApiAppSecret))

_, err= mac.Write([]byte(signingStr))
if err != nil {
log.Fatal(err)
}
signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))
sign := fmt.Sprintf("hmac id=\"%s\", algorithm=\"hmac-sha1\", headers=\"x-date\", signature=\"%s\"",
ApiAppKey, signature)

// Construct the request
headers := map[string]string{
"Host": Host,
"Accept": Accept,
"Content-Type": ContentType,
"x-date": xDate,
"Authorization": sign,
}

// Send the request
req, err := http.NewRequest(HTTPMethod, Url, strings.NewReader(bodyStr))
if err != nil {
log.Fatal(err)
}

for k, v := range headers {
req.Header.Add(k, v)
}

res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()

resBody, _ := ioutil.ReadAll(res.Body)

fmt.Println(string(resBody))
}


Sample code with the request body in form-data format

package main

import (
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"sort"
"strings"
"time"
)

func main() {
// Application's `ApiAppKey`
const ApiAppKey = "Your ApiAppKey"
// Application's `ApiAppSecret`
const ApiAppSecret = "Your ApiAppSecret"

const Url = "http://service-xxx-xxx.gz.apigw.tencentcs.com/"

const GmtFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
const HTTPMethod = "POST"
const Accept = "application/json"
const ContentType = "application/x-www-form-urlencoded"

// Parse `Host` and `Path` according to `Url`
u, err := url.Parse(Url)
if err != nil {
log.Fatal(err)
}
Host := u.Hostname()
Path := u.Path
Query := u.RawQuery

// Environment information is not included in the signature path
if strings.HasPrefix(Path, "/release") {
Path = strings.TrimPrefix(Path, "/release")
}else if strings.HasPrefix(Path, "/test") {
Path = strings.TrimPrefix(Path, "/test")
}else if strings.HasPrefix(Path, "/prepub") {
Path = strings.TrimPrefix(Path, "/prepub")
}

if Path == "" {
Path = "/"
}

// Splice query parameters. The query parameters need to be sorted in lexicographical order. In this demo, it is assumed the parameters are already sorted.
if len(Query) > 0 {
Path = Path + "?" + Query
}

// Get the current UTC time
xDate := time.Now().UTC().Format(GmtFormat)
ContentMD5 := ""

// Request body form data
body := map[string]string{
"arg1": "a",
"arg2": "b",
}
var bodyKeys []string
for k := range body {
bodyKeys = append(bodyKeys, k)
}

var bodyBuilder strings.Builder
sort.Strings(bodyKeys)
for _, k := range bodyKeys {
bodyBuilder.WriteString(fmt.Sprintf("%s=%s&", k, body[k]))
}
bodyStr := bodyBuilder.String()
// Remove the last `&`
bodyStr = bodyStr[:len(bodyStr) - 1]

// Construct the signature
signingStr := fmt.Sprintf("x-date: %s\n%s\n%s\n%s\n%s\n%s?%s", xDate, HTTPMethod, Accept, ContentType,
ContentMD5, Path, bodyStr)
mac := hmac.New(sha1.New, []byte(ApiAppSecret))

_, err = mac.Write([]byte(signingStr))
if err != nil {
log.Fatal(err)
}
signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))
sign := fmt.Sprintf("hmac id=\"%s\", algorithm=\"hmac-sha1\", headers=\"x-date\", signature=\"%s\"",
ApiAppKey, signature)

// Construct the request
headers := map[string]string{
"Host": Host,
"Accept": Accept,
"Content-Type": ContentType,
"x-date": xDate,
"Authorization": sign,
}

// Send the request
req, err := http.NewRequest(HTTPMethod, Url, strings.NewReader(bodyStr))
if err != nil {
log.Fatal(err)
}

for k, v := range headers {
req.Header.Add(k, v)
}

res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()

resBody, _ := ioutil.ReadAll(res.Body)

fmt.Println(string(resBody))
}


Sample code according to the hmac_sm3 algorithm

For more information, see Sample Project.
package main

import (
"crypto/md5"
"encoding/base64"
"encoding/hex"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"sort"
"strings"
"time"
"unsafe"
)

/*
#cgo CFLAGS: -I./
#cgo LDFLAGS: -L./ -lTencentSM
#include "sm.h" // Quotation mark is used because it is not a standard "C" header file
*/
import "C"


func mySM3_HMAC(data []byte, dataLen int, key []byte, keyLen int, mac []byte, macLen int) int {
if data == nil || key == nil || mac == nil || len(mac) != macLen {
panic("invalid parameter")
}
return int(C.SM3_HMAC((*C.uchar)(unsafe.Pointer(&data[0])), (C.size_t)(dataLen),
(*C.uchar)(unsafe.Pointer(&key[0])), (C.size_t)(keyLen), (*C.uchar)(unsafe.Pointer(&mac[0]))))
}

func main() {
// Application's `ApiAppKey`
const ApiAppKey = "Your ApiAppKey"
// Application's `ApiAppSecret`
const ApiAppSecret = "Your ApiAppSecret"

const Url = "http://service-xxx-xxx.gz.apigw.tencentcs.com/a?c=1&b=3"

const GmtFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
const HTTPMethod = "GET"
const Accept = "application/json"
const ContentType = "application/json"

// Parse `Host` and `Path` according to `Url`
u, err := url.Parse(Url)
if err != nil {
log.Fatal(err)
}
Host:= u.Hostname()
Path:= u.Path
Query := u.RawQuery

// Environment information is not included in the signature path
if strings.HasPrefix(Path, "/release") {
Path = strings.TrimPrefix(Path, "/release")
}else if strings.HasPrefix(Path, "/test") {
Path = strings.TrimPrefix(Path, "/test")
}else if strings.HasPrefix(Path, "/prepub") {
Path = strings.TrimPrefix(Path, "/prepub")
}

if Path == "" {
Path = "/"
}

// Splice query parameters. The query parameters need to be sorted in lexicographical order.
if len(Query) > 0 {
args, _ := url.ParseQuery(Query)

var keys []string
for k := range args {
keys = append(keys, k)
}
sort.Strings(keys)

sortQuery := ""
for _, k := range keys {
if args[k][0] != "" {
sortQuery = sortQuery + "&" + k + "=" + args[k][0]
} else {
sortQuery = sortQuery + "&" + k
}
}
sortQuery = strings.TrimPrefix(sortQuery, "&")

Path = Path + "?" + sortQuery
}

// Get the current UTC time
xDate := time.Now().UTC().Format(GmtFormat)
ContentMD5 := ""
bodyStr := `{"arg1":"a","arg2":"b"}`
if HTTPMethod == "POST" {
h := md5.New()
h.Write([]byte(bodyStr))
md5Str := hex.EncodeToString(h.Sum(nil))
ContentMD5 = base64.StdEncoding.EncodeToString([]byte(md5Str))
}

// Construct the signature
signingStr := fmt.Sprintf("x-date: %s\n%s\n%s\n%s\n%s\n%s", xDate, HTTPMethod, Accept, ContentType,
ContentMD5, Path)

data := []byte(signingStr)
key := []byte(ApiAppSecret)
var out [32]byte

mySM3_HMAC(data[:], len(data), key[:], len(key), out[:], len(out))
signature := base64.StdEncoding.EncodeToString(out[:])

sign := fmt.Sprintf("hmac id=\"%s\", algorithm=\"hmac-sm3\", headers=\"x-date\", signature=\"%s\"",
ApiAppKey, signature)

// Construct the request
headers := map[string]string{
"Host": Host,
"Accept": Accept,
"Content-Type": ContentType,
"x-date": xDate,
"Authorization": sign,
}

// Send the request
req, err := http.NewRequest(HTTPMethod, Url, strings.NewReader(bodyStr))
if err != nil {
log.Fatal(err)
}

for k, v := range headers {
req.Header.Add(k, v)
}

res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()

resBody, _ := ioutil.ReadAll(res.Body)

fmt.Println(string(resBody))
}

Was this page helpful?
You can also Contact Sales or Submit a Ticket for help.
Yes
No

Feedback

Contact Us

Contact our sales team or business advisors to help your business.

Technical Support

Open a ticket if you're looking for further assistance. Our Ticket is 7x24 avaliable.

7x24 Phone Support