Function Compute supports signature authentication for HTTP triggers. Gateways of Function Compute authenticate requests that are sent to HTTP triggers for which signature authentication is enabled. This allows you to focus on business logic without the need to manually authenticate the signatures in requests. This topic describes how to configure signature authentication for HTTP triggers in the Function Compute console. This topic also describes how to trigger HTTP triggers by using signatures in requests.
Enable signature authentication for HTTP triggers
This section describes how to enable signature authentication for an existing HTTP trigger of a function. You must create a web function in advance. For more information, see Create a function.
Log on to the Function Compute console. In the left-side navigation pane, click Function.
In the top navigation bar, select a region. On the Function page, click the function that you want to manage.
On the function details page, click the Configuration tab. In the left-side navigation tree, click Trigger. Then, find the trigger that you want to manage and click Modify in the Actions column.
In the Modify Trigger panel, set Authentication Method to Signature Authentication and click OK.
Access the URL of an HTTP trigger by using a signature in a request
The Alibaba Cloud signature method for SDKs is used. For more information, see Signature method. Alibaba Cloud SDKs provide a signature method for various programming languages. The following items describe the process to use a signature in a request:
Use an Alibaba Cloud SDK to generate a signature string.
Include the signature string in the Authorization header of an HTTP request.
Use an HTTP client to initiate the request.
Signature SDKs
Alibaba Cloud provides signature SDKs for various programming languages. This section provides a convenient method to install a signature SDK.
Language | SDK |
Golang | go get github.com/alibabacloud-go/openapi-util/service |
Python | pip install alibabacloud-openapi-util |
Node.js | npm install @alicloud/openapi-util |
Java |
|
Examples
This section provides sample requests in different programming languages for your reference. For more information about the complete signature method, see Signature method.
# -*- 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. If you use Security Token Service (STS), you must specify this parameter.
method = 'POST'
body = 'hello world'
url = 'https://xx.cn-shanghai.fcapp.run/hello?foo=bar' # The URL of your HTTP trigger.
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
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. If you use Security Token Service (STS), you must specify this parameter.
const method = 'POST';
const body = 'hello world';
const url='https://xx.cn-shanghai.fcapp.run/hello?foo=bar' // The URL of your HTTP trigger.
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;
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. If you use Security Token Service (STS), you must specify this parameter.
method := "POST"
body := "hello world"
url = 'https://xx.cn-shanghai.fcapp.run/hello?foo=bar' # The URL of your HTTP trigger.
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. If you use Security Token Service (STS), you must specify this parameter.
if (securityToken == null) {
securityToken = "";
}
String method = "POST";
String body = "hello world";
String url = "https://xx.cn-shanghai.fcapp.run/hello?foo=bar"; // The URL of your HTTP trigger.
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);
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
In this example, Go is used to show you how to access an HTTP trigger by including a signature in your request.
Run the
go get github.com/alibabacloud-go/openapi-util/service
command to install the SDK.Prepare the
main.go
file on your on-premises machine.You can directly use the sample code provided in this topic. For more information, see Examples.
Run
go run main.go
to run the code.If the following information is returned, the code runs successfully and the function has returned a response.
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 does the message "required HTTP header Date was not specified" appear when I access an HTTP trigger for which signature authentication is enabled?
Your request does not pass the signature authentication due to the following reasons:
The request does not contain a signature.
The request contains a signature but does not contain the Date header.
Why does the message "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" appear when I invoke a function by using an HTTP trigger for which signature authentication is enabled?
The message indicates that the signature has expired. Use the current point in time to re-sign the request.
Why does the message "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" appear when I invoke a function by using an HTTP trigger for which signature authentication is enabled?
The authentication fails because the signature in the request is inconsistent with the signature calculated by Function Compute.