全部產品
Search
文件中心

Function Compute:為HTTP觸發器配置簽名認證

更新時間:Jul 06, 2024

Function Compute支援為HTTP觸發器配置簽名認證,當請求訊息到達Function Compute網關後,網關會對開啟簽名認證的HTTP觸發器上的請求進行認證,您的函數無需再次對請求籤名進行認證,只需關注商務邏輯即可。本文介紹如何通過控制台為HTTP觸發器配置簽名認證以及如何驗證通過簽名訪問HTTP觸發器。

開啟HTTP觸發器簽名認證

本文介紹如何在函數已有的HTTP觸發器中開啟簽名認證,您需要先建立Web函數,具體操作,請參見建立函數

  1. 登入Function Compute控制台,在左側導覽列,單擊函數

  2. 在頂部功能表列,選擇地區,然後在函數頁面,單擊目標函數。

  3. 在函數配置頁面,選擇配置頁簽,在左側導覽列,單擊觸發器,然後單擊目標觸發器右側操作列的編輯

  4. 在編輯觸發程序面板,將認證方式修改為簽名認證,然後單擊確定

    image.png

通過簽名訪問HTTP觸發器地址

HTTP觸發器的簽名方式遵循阿里雲SDK的簽名機制,詳情請參見簽名機制。阿里雲SDK提供了各種語言的簽名方法,使用流程如下:

  1. 通過阿里雲SDK產生簽名字串。

  2. 將簽名字串設定到HTTP請求的Authorization Header中。

  3. 使用任意的HTTP用戶端發起請求。

各語言簽名SDK

阿里雲提供的各語言簽名SDK,您可以使用如下捷徑安裝。

語言類型

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

<dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>openapiutil</artifactId>
  <version>0.2.1</version>
</dependency>
<dependency>
  <groupId>com.aliyun</groupId>
  <artifactId>tea-openapi</artifactId>
  <version>0.3.1</version>
</dependency>    

各語言請求樣本

本文提供以下請求樣本,僅供參考,完整的簽名機制請參見簽名機制

# -*- 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', '')   # 可選,使用STS時需要提供

method = 'POST'
body = 'hello world'
url = 'https://xx.cn-shanghai.fcapp.run/hello?foo=bar'   # 你的HTTP觸發器地址
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'] || ''; // 可選,使用STS時需要提供

    const method = 'POST';
    const body = 'hello world';
    const url = 'https://xx.cn-shanghai.fcapp.run/hello?foo=bar' // 你的HTTP觸發器地址
    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")) // 可選,使用STS時需要提供

	method := "POST"
	body := "hello world"
	url := "https://xx.cn-shanghai.fcapp.run/hello?foo=bar" // 你的HTTP觸發器地址
	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");  // 可選,使用STS時需要提供
        if (securityToken == null) {
            securityToken = "";
        }

        String method = "POST";
        String body = "hello world";
        String url = "https://xx.cn-shanghai.fcapp.run/hello?foo=bar";  // 你的HTTP觸發器地址
        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);
        }
    }
}

操作步驟

本文以Go語言為例,示範如何通過簽名訪問HTTP觸發器。

  1. 執行go get github.com/alibabacloud-go/openapi-util/service安裝SDK。

  2. 在本地準備代碼檔案main.go

    您可以直接使用本文提供的範例程式碼,詳情請參見各語言請求樣本

  3. 執行go run main.go運行代碼。

    執行成功後返回結果如下,表示已正確地擷取函數的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!

常見問題

為什麼HTTP觸發器開啟簽名認證之後,通過HTTP觸發器訪問函數提示:required HTTP header Date was not specified?

該提示說明認證失敗,可能原因如下:

  1. 沒有在請求中進行簽名。

  2. 在請求中做了簽名,但是沒有提供Date這個Header。

為什麼HTTP觸發器開啟簽名認證之後,通過HTTP觸發器訪問函數提示: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?

該提示說明簽名到期,請您重新使用目前時間進行簽名。

為什麼HTTP觸發器開啟簽名認證之後,通過HTTP觸發器訪問函數提示:The request signature we calculated does not match the signature you provided. Check your access key and signing method?

請求中的簽名與Function Compute計算得到的簽名不一致,認證失敗。