Function Compute supports configuring signature authentication for HTTP triggers. When a request reaches the Function Compute gateway, the gateway authenticates requests on HTTP triggers with signature authentication enabled. Your function does not need to re-authenticate the request signature. Focus on your business logic. This topic describes how to configure signature authentication for HTTP triggers using the console and how to verify access to HTTP triggers using signatures.
Enable Signature Authentication for HTTP Triggers
This topic describes how to enable signature authentication for existing HTTP triggers. Create a function first. 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 Trigger tab. Then, in the Actions column to the right of the target trigger, click Modify.
In the Edit Trigger panel, set Authentication Method to Signature Authentication. Then, click OK.
Access HTTP Trigger Addresses Using Signatures
HTTP triggers follow the Alibaba Cloud SDK's signature mechanism. For more information, see Signature Mechanism. The Alibaba Cloud SDK provides signing methods for various languages. The process is as follows:
Generate a signature string using the Alibaba Cloud SDK.
Set the signature string in the Authorization header of the HTTP request.
Initiate the request using any HTTP client.
Signature SDKs for Various Languages
Alibaba Cloud provides signature SDKs for various languages. Install them using the following shortcuts.
Language Type | 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 | |
Request Examples for Various Languages
This topic provides the following request examples for reference only. For the complete 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 using STS.
# The method parameter must be uppercase, such as POST or GET. If your request method is GET, change requests.post to requests.get below.
method = 'POST'
body = 'hello world'
url = 'https://xx.cn-shanghai.fcapp.run/hello?foo=bar' # Your HTTP trigger address
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 the method is GET, change requests.post to requests.get below.
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 using STS.
// The method parameter must be uppercase, such as POST or GET. If your request method is GET, change axios.post to axios.get below.
const method = 'POST';
const body = 'hello world';
const url = 'https://xx.cn-shanghai.fcapp.run/hello?foo=bar' // Your HTTP trigger address
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 the method is GET, change axios.post to axios.get below.
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 using STS.
// The method parameter must be uppercase.
method := "POST"
body := "hello world"
url := "https://xx.cn-shanghai.fcapp.run/hello?foo=bar" // Your HTTP trigger address
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 using STS.
if (securityToken == null) {
securityToken = "";
}
// The method parameter must be uppercase, such as POST or GET. If your request method is GET, change HttpPost to HttpGet below.
String method = "POST";
String body = "hello world";
String url = "https://xx.cn-shanghai.fcapp.run/hello?foo=bar"; // Your HTTP trigger address
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 the method is GET, change HttpPost to HttpGet below.
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 demonstrate how to access HTTP triggers using signatures.
Run
go get github.com/alibabacloud-go/openapi-util/serviceto install the SDK.Prepare the code file
main.golocally.You can use the example code provided in this topic. For more information, see Request Examples for Various Languages.
Run the code by executing
go run main.go.A successful execution returns the following result, indicating that the function's response was correctly obtained.
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 accessing a function through an HTTP trigger, after enabling signature authentication, prompt: 'required HTTP header Date was not specified'?
This prompt indicates authentication failure. Possible reasons are as follows:
No signature in the request.
A signature was included in the request, but the Date header was not provided.
Why does accessing a function through an HTTP trigger, after enabling signature authentication, prompt: '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'?
This prompt indicates that the signature has expired. Re-sign using the current time.
Why does accessing a function through an HTTP trigger, after enabling signature authentication, prompt: 'The request signature we calculated does not match the signature you provided. Check your access key and signing method'?
The signature in the request does not match the signature calculated by Function Compute. Authentication failed.