Function Compute supports signature authentication for HTTP triggers. When signature authentication is enabled for a trigger, the Function Compute gateway authenticates the request. Your function does not need to authenticate the request signature, which lets you focus on your business logic. This topic describes how to configure signature authentication for an HTTP trigger in the console and how to verify access to the trigger using a signature.
Enable signature authentication for an HTTP trigger
This section describes how to enable signature authentication for an existing HTTP trigger. You must first create a function. For more information, see Create a function.
Log on to the Function Compute console. In the left-side navigation pane, click Functions.
In the top navigation bar, select a region. On the Functions page, click the function that you want to manage.
On the function configuration page, select the Triggers tab. Then, in the Actions column of the target trigger, click Edit.
In the Edit Trigger panel, set Authentication Method to Signature Authentication. Then, click OK.
Access an HTTP trigger URL using a signature
The signature method for HTTP triggers follows the signature mechanism of Alibaba Cloud SDKs. For more information, see Signature mechanism. Alibaba Cloud SDKs provide signature methods for various languages. The process is as follows:
Generate a signature string using an Alibaba Cloud SDK.
Set the signature string in the Authorization header of the HTTP request.
Use any HTTP client to send the request.
Signature SDKs for different languages
Use the following shortcuts to install the Alibaba Cloud signature SDKs for different languages.
Language | SDK |
Go | go get github.com/alibabacloud-go/openapi-util/service |
Python | pip install alibabacloud-openapi-util |
Node.js | npm install @alicloud/openapi-util |
Java | |
Request examples for different languages
The following request examples are for reference only. For complete details about the signature mechanism, see Signature mechanism.
# -*- coding: utf-8 -*-
import os
from datetime import datetime
from urllib.parse import urlparse, parse_qs
import requests
from alibabacloud_openapi_util.client import Client as util
from Tea.request import TeaRequest
accessKeyId = os.environ['ALIBABA_CLOUD_ACCESS_KEY_ID']
accessKeySecret = os.environ['ALIBABA_CLOUD_ACCESS_KEY_SECRET']
securityToken = os.environ.get('ALIBABA_CLOUD_SECURITY_TOKEN', '') # Optional. Required when you use STS.
# The method parameter must be in uppercase, such as POST or GET. If you use the GET method, change requests.post to requests.get.
method = 'POST'
body = 'hello world'
url = 'https://xx.cn-shanghai.fcapp.run/hello?foo=bar' # Your HTTP trigger URL
date = datetime.utcnow().isoformat('T')[:19]+'Z'
headers = {
'x-acs-date': date,
'x-acs-security-token': securityToken
}
parsedUrl = urlparse(url)
authRequest = TeaRequest()
authRequest.method = method
authRequest.pathname = parsedUrl.path.replace('$', '%24')
authRequest.headers = headers
authRequest.query = {k: v[0] for k, v in parse_qs(parsedUrl.query).items()}
auth = util.get_authorization(authRequest, 'ACS3-HMAC-SHA256', '', accessKeyId, accessKeySecret)
headers['authorization'] = auth
# If you use the GET method, change requests.post to requests.get.
resp = requests.post(url, body, headers=headers)
print(resp.text)
const util = require("@alicloud/openapi-util");
const axios = require('axios');
async function main() {
const accessKeyId = process.env['ALIBABA_CLOUD_ACCESS_KEY_ID'];
const accessKeySecret = process.env['ALIBABA_CLOUD_ACCESS_KEY_SECRET'];
const securityToken = process.env['ALIBABA_CLOUD_SECURITY_TOKEN'] || ''; // Optional. Required when you use STS.
// The method parameter must be in uppercase, such as POST or GET. If you use the GET method, change axios.post to axios.get.
const method = 'POST';
const body = 'hello world';
const url = 'https://xx.cn-shanghai.fcapp.run/hello?foo=bar' // Your HTTP trigger URL
const date = new Date().toISOString();
let headers = {
'x-acs-date': date,
'x-acs-security-token': securityToken
};
const parsedUrl = new URL(url);
const authRequest = {
method: method,
pathname: parsedUrl.pathname.replace('$', '%24'),
headers: headers,
query: Object.fromEntries(parsedUrl.searchParams),
};
console.log('auth: ', authRequest);
const auth = util.default.getAuthorization(authRequest, 'ACS3-HMAC-SHA256', '', accessKeyId, accessKeySecret);
headers['authorization'] = auth;
// If you use the GET method, change axios.post to axios.get.
const resp = await axios.post(url, body, {
headers: headers,
});
console.log('resp: ', resp.data);
}
main().catch(console.error);
package main
import (
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"time"
openapiutil "github.com/alibabacloud-go/openapi-util/service"
"github.com/alibabacloud-go/tea/tea"
)
func main() {
accessKeyId := tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
accessKeySecret := tea.String(os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"))
securityToken := tea.String(os.Getenv("ALIBABA_CLOUD_SECURITY_TOKEN")) // Optional. Required when you use STS.
// The method parameter must be in uppercase.
method := "POST"
body := "hello world"
url := "https://xx.cn-shanghai.fcapp.run/hello?foo=bar" // Your HTTP trigger URL
req, err := http.NewRequest(method, url, strings.NewReader(body))
if err != nil {
log.Printf("new request error: %v", err)
return
}
date := time.Now().UTC().Format(time.RFC3339)
req.Header.Set("x-acs-date", date)
req.Header.Set("x-acs-security-token", *securityToken)
authRequest := &tea.Request{
Method: &method,
Pathname: tea.String(strings.ReplaceAll(req.URL.Path, "$", "%24")),
Headers: make(map[string]*string),
Query: make(map[string]*string),
}
for k := range req.URL.Query() {
authRequest.Query[k] = tea.String(req.URL.Query().Get(k))
}
for k := range req.Header {
authRequest.Headers[k] = tea.String(req.Header.Get(k))
}
auth := openapiutil.GetAuthorization(authRequest, tea.String("ACS3-HMAC-SHA256"), nil, accessKeyId, accessKeySecret)
req.Header.Set("authorization", *auth)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Printf("post error: %v", err)
return
}
defer resp.Body.Close()
buf, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("read body error: %v", err)
return
}
log.Printf("resp: %v, body: %s", resp, string(buf))
}
package com.aliyun.sample;
import org.apache.http.NameValuePair;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import com.aliyun.tea.*;
public class Sample {
public static void main(String[] args_) throws Exception {
String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
String securityToken = System.getenv("ALIBABA_CLOUD_SECURITY_TOKEN"); // Optional. Required when you use STS.
if (securityToken == null) {
securityToken = "";
}
// The method parameter must be in uppercase, such as POST or GET. If you use the GET method, change HttpPost to HttpGet.
String method = "POST";
String body = "hello world";
String url = "https://xx.cn-shanghai.fcapp.run/hello?foo=bar"; // Your HTTP trigger URL
Map<String, String> headers = new HashMap<String, String>();
String date = Instant.now().toString();
headers.put("x-acs-date", date);
headers.put("x-acs-security-token", securityToken);
URI uri = new URI(url);
Map<String, String> query = new HashMap<String, String>();
for (NameValuePair pair : URLEncodedUtils.parse(uri, StandardCharsets.UTF_8)) {
query.put(pair.getName(), pair.getValue());
}
TeaRequest req = new TeaRequest();
req.method = method;
req.pathname = uri.getPath().replace("$", "%24");
req.headers = headers;
req.query = query;
String auth = com.aliyun.openapiutil.Client.getAuthorization(
req, "ACS3-HMAC-SHA256", "", accessKeyId, accessKeySecret);
headers.put("authorization", auth);
// If you use the GET method, change HttpPost to HttpGet.
HttpPost request = new HttpPost(url);
for (Map.Entry<String, String> entry : headers.entrySet()) {
request.setHeader(entry.getKey(), entry.getValue());
}
StringEntity entity = new StringEntity(body);
request.setEntity(entity);
// Execute the request
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
org.apache.http.HttpResponse response = httpClient.execute(request);
String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
System.out.println(responseString);
}
}
}
Procedure
This topic uses Go as an example to show how to access an HTTP trigger using a signature.
Run
go get github.com/alibabacloud-go/openapi-util/serviceto install the SDK.Prepare the
main.gocode file on your local machine.You can use the sample code provided in this topic. For more information, see Request examples for different languages.
Run
go run main.goto run the code.If the code runs successfully, the following result is returned. This indicates that the function response is correctly retrieved.
2024/02/22 17:21:31 resp: &{200 OK 200 HTTP/1.1 1 1 map[Access-Control-Expose-Headers:[Date,x-fc-request-id] Content-Disposition:[attachment] Content-Length:[14] Content-Type:[text/plain; charset=utf-8] Date:[Thu, 22 Feb 2024 09:21:31 GMT] X-Fc-Request-Id:[1-65d71219-15d63510-fecf237c590c]] 0xc000120040 14 [] false false map[] 0xc000100100 0xc0000e0370}, body: Hello, Golang!
FAQ
Why do I receive the "required HTTP header Date was not specified" error when I access a function through an HTTP trigger with signature authentication enabled?
This error indicates that the authentication failed. The possible causes are as follows:
The request is not signed.
The request is signed, but the Date header is not provided.
Why do I receive the "the difference between the request time 'Thu, 04 Jan 2024 01:33:13 GMT' and the current time 'Thu, 04 Jan 2024 08:34:58 GMT' is too large" error when I access a function through an HTTP trigger with signature authentication enabled?
This error indicates that the signature has expired. Sign the request again using the current time.
Why do I receive "The request signature we calculated does not match the signature you provided. Check your access key and signing method" error when I access a function through an HTTP trigger with signature authentication enabled?
This error occurs because the signature in the request does not match the signature calculated by Function Compute, which causes the authentication to fail.