Function Compute では、HTTP トリガーに対する署名認証の設定がサポートされています。リクエストが Function Compute ゲートウェイに到達すると、署名認証が有効化された HTTP トリガーに対してゲートウェイが自動的に認証を行います。関数側でリクエストの署名を再認証する必要はありません。ビジネスロジックに集中してください。本トピックでは、コンソールを用いた HTTP トリガーの署名認証の設定方法および署名を用いた HTTP トリガーへのアクセス検証方法について説明します。
HTTP トリガーの署名認証の有効化
本トピックでは、既存の HTTP トリガーに対して署名認証を有効化する手順について説明します。まず、関数を作成してください。詳細については、「関数の作成」をご参照ください。
Function Compute コンソール にログインします。左側のナビゲーションウィンドウで、 を選択します。
上部のナビゲーションバーからリージョンを選択します。関数 ページで、対象の関数をクリックします。
関数構成ページで、トリガー タブを選択します。その後、対象のトリガーの右側にある 操作 列から、変更 をクリックします。
トリガー編集パネルで、認証方法 を 署名認証 に設定し、OK をクリックします。
署名を用いた HTTP トリガーのアドレスへのアクセス
HTTP トリガーは Alibaba Cloud SDK の署名メカニズムに従います。詳細については、「署名メカニズム」をご参照ください。Alibaba Cloud SDK では、さまざまなプログラミング言語向けの署名メソッドが提供されています。そのプロセスは以下のとおりです:
Alibaba Cloud SDK を使用して署名文字列を生成します。
HTTP リクエストの Authorization ヘッダーに署名文字列を設定します。
任意の HTTP クライアントを使用してリクエストを送信します。
各種プログラミング言語向けの署名 SDK
Alibaba Cloud では、各種プログラミング言語向けの署名 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 | |
さまざまなプログラミング言語でのリクエストの例
本トピックでは、参考用として以下のリクエスト例を提供します。完全な署名メカニズムについては、「署名メカニズム」をご参照ください。
# -*- 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 を使用する場合に必須。
# メソッドパラメーターは大文字である必要があります(例:POST や GET)。リクエストメソッドが GET の場合は、下記の requests.post を requests.get に変更してください。
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
# メソッドが GET の場合は、下記の requests.post を 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'] || ''; // オプション。STS を使用する場合に必須。
// メソッドパラメーターは大文字である必要があります(例:POST や GET)。リクエストメソッドが GET の場合は、下記の axios.post を axios.get に変更してください。
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;
// メソッドが GET の場合は、下記の axios.post を 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")) // オプション。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 = "";
}
// メソッドパラメーターは大文字である必要があります(例:POST や GET)。リクエストメソッドが GET の場合は、下記の HttpPost を HttpGet に変更してください。
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);
// メソッドが GET の場合は、下記の HttpPost を 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);
// リクエストを実行
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);
}
}
}
操作手順
本トピックでは、Golang を例として、署名を用いた HTTP トリガーへのアクセス方法を説明します。
SDK をインストールするために、
go get github.com/alibabacloud-go/openapi-util/serviceを実行します。ローカルにコードファイル
main.goを準備します。本トピックで提供されているサンプルコードを使用できます。詳細については、「各種プログラミング言語向けのリクエスト例」をご参照ください。
go run main.goを実行してコードを実行します。正常に実行された場合、以下の結果が返され、関数からの応答が正しく取得できたことを示します。
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 トリガー経由で関数にアクセスすると「required HTTP header Date was not specified」というエラーが表示されるのはなぜですか?
このメッセージは認証失敗を示しています。考えられる原因は以下のとおりです:
リクエストに署名が含まれていない。
リクエストに署名は含まれているが、Date ヘッダーが指定されていない。
署名認証を有効化した後、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 トリガー経由で関数にアクセスすると「The request signature we calculated does not match the signature you provided. Check your access key and signing method」というエラーが表示されるのはなぜですか?
リクエスト内の署名が Function Compute が計算した署名と一致していないため、認証に失敗しています。