表格存储支持 V4 签名算法,通过派生密钥替代AccessKey Secret 直接参与身份验证,降低密钥泄露的影响范围。派生密钥仅对特定地域和产品当天有效,次日自动失效。
V4 签名工作原理
V4 签名用派生密钥替代AccessKey Secret 直接参与身份验证。派生密钥由AccessKey Secret、日期、地域和产品码四个要素通过 HMAC 计算链推导得出:
HMAC(HMAC(HMAC(AccessKey Secret, 日期), 地域), 产品码) → 派生密钥
正因如此,即使某个派生密钥泄露,影响也严格限制在特定日期、特定地域和特定产品范围内,不会波及同账号下其他地域或其他产品的资源。此外,派生密钥次日自动失效,无需手动撤销。
使用 V4 签名的同时,建议将AccessKey配置为环境变量,避免硬编码在代码中,进一步降低密钥泄露风险。
请求流程
客户端使用 V4 签名算法,基于AccessKey计算生成派生密钥,并以派生密钥发起请求。
服务端接收请求后,使用派生密钥对调用方身份进行验证。
-
验证通过后,服务端处理请求并返回结果。
说明验证未通过时,服务端拒绝客户端访问。
客户端接收服务端返回的处理结果。
示例代码
表格存储 Java SDK 5.16.1 及以上版本支持 V4 签名功能。使用前请确认SDK版本满足要求。
使用AccessKey初始化
以下示例以阿里云账号或RAM用户的AccessKey为例介绍如何配置访问凭证。AccessKey 的获取方式,请参见 如何获取AccessKey 。
以下示例代码使用 V4 签名初始化 Tablestore Client,获取实例下的数据表列表并打印到控制台。
示例 1(推荐):仅需提供 AccessKey,派生密钥由SDK自动计算和刷新,无需手动维护。
示例 2:同时提供AccessKey与派生密钥(
v4SigningAccessKey)。派生密钥次日自动失效,必须自行实现定时刷新机制,否则过期后将无法访问表格存储服务。
import com.alicloud.openservices.tablestore.SyncClient;
import com.alicloud.openservices.tablestore.core.ResourceManager;
import com.alicloud.openservices.tablestore.core.auth.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import static com.alicloud.openservices.tablestore.core.Constants.PRODUCT;
import static com.alicloud.openservices.tablestore.core.Constants.SIGNING_KEY_SIGN_METHOD;
public class InitClientV4 {
public static void main(String[] args) {
// yourRegion 填写您的实例所在地域,如 cn-hangzhou
final String region = "yourRegion";
// yourInstanceName 填写您的实例名称
final String instanceName = "yourInstanceName";
// yourEndpoint 填写您的实例访问地址
final String endpoint = "yourEndpoint";
// 获取系统变量里的 AccessKey ID 和 AccessKey Secret
final String accessKeyId = System.getenv("TABLESTORE_ACCESS_KEY_ID");
final String accessKeySecret = System.getenv("TABLESTORE_ACCESS_KEY_SECRET");
{
/**
* 示例一:使用原始的accessKeyId,accessKeySecret -> 先构造{@link DefaultCredentials },再生成 {@link V4Credentials }
*/
DefaultCredentials credentials = new DefaultCredentials(accessKeyId, accessKeySecret);
V4Credentials credentialsV4 = V4Credentials.createByServiceCredentials(credentials, region);
CredentialsProvider provider = new DefaultCredentialProvider(credentialsV4);
/**
* using {@link V4Credentials } initialize tableStore client
*/
SyncClient client = new SyncClient(endpoint, provider, instanceName, null, new ResourceManager(null, null));
// do something
client.listTable().getTableNames().forEach(System.out::println);
// shutdown tableStore client
client.shutdown();
}
{
/**
* 示例二:直接使用accessKey与派生密钥 -> 直接构造{@link V4Credentials }
*/
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
String signDate = dateFormat.format(new Date()); // signDate格式如同"20230527"
String v4SigningAccessKey = CalculateV4SigningKeyUtil.finalSigningKeyString(accessKeySecret, signDate, region, PRODUCT, SIGNING_KEY_SIGN_METHOD); // 派生密钥
V4Credentials credentialsV4 = new V4Credentials(accessKeyId, v4SigningAccessKey, region, signDate);
CredentialsProvider provider = new DefaultCredentialProvider(credentialsV4);
/**
* using {@link V4Credentials } initialize tableStore client
*/
SyncClient client = new SyncClient(endpoint, provider, instanceName, null, new ResourceManager(null, null));
// do something
client.listTable().getTableNames().forEach(System.out::println);
// shutdown tableStore client
client.shutdown();
}
}
}
使用STS初始化
如何获取 STS 临时访问凭证,请参见 使用STS临时访问凭证访问表格存储 。
以下示例代码使用 V4 签名初始化 Tablestore Client,获取实例下的数据表列表并打印到控制台。
示例 1(推荐):仅需提供 STS 临时访问凭证,派生密钥由SDK自动计算和刷新,无需手动维护。
示例 2:同时提供 STS 临时访问凭证与派生密钥(
v4SigningAccessKey)。派生密钥次日自动失效,必须自行实现定时刷新机制,否则过期后将无法访问表格存储服务。
import com.alicloud.openservices.tablestore.SyncClient;
import com.alicloud.openservices.tablestore.core.ResourceManager;
import com.alicloud.openservices.tablestore.core.auth.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import static com.alicloud.openservices.tablestore.core.Constants.PRODUCT;
import static com.alicloud.openservices.tablestore.core.Constants.SIGNING_KEY_SIGN_METHOD;
public class InitClientV4 {
public static void main(String[] args) {
// yourRegion 填写您的实例所在地域,如 cn-hangzhou
final String region = "yourRegion";
// yourInstanceName 填写您的实例名称
final String instanceName = "yourInstanceName";
// yourEndpoint 填写您的实例访问地址
final String endpoint = "yourEndpoint";
// 获取环境变量里的 STS AccessKey ID、STS AccessKey Secret 和 STS Token
final String accessKeyId = System.getenv("TABLESTORE_ACCESS_KEY_ID");
final String accessKeySecret = System.getenv("TABLESTORE_ACCESS_KEY_SECRET");
final String securityToken = System.getenv("TABLESTORE_SESSION_TOKEN");
{
/**
* 示例一:使用原始的accessKeyId,accessKeySecret,securityToken -> 先构造{@link DefaultCredentials },再生成 {@link V4Credentials }
*/
DefaultCredentials credentials = new DefaultCredentials(accessKeyId, accessKeySecret, securityToken);
V4Credentials credentialsV4 = V4Credentials.createByServiceCredentials(credentials, region);
CredentialsProvider provider = new DefaultCredentialProvider(credentialsV4);
/**
* using {@link V4Credentials } initialize tableStore client
*/
SyncClient client = new SyncClient(endpoint, provider, instanceName, null, new ResourceManager(null, null));
// do something
client.listTable().getTableNames().forEach(System.out::println);
// shutdown tableStore client
client.shutdown();
}
{
/**
* 示例二:直接使用accessKey与派生密钥 -> 直接构造{@link V4Credentials }
*/
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
String signDate = dateFormat.format(new Date()); // signDate格式如同"20230527"
String v4SigningAccessKey = CalculateV4SigningKeyUtil.finalSigningKeyString(accessKeySecret, signDate, region, PRODUCT, SIGNING_KEY_SIGN_METHOD);
V4Credentials credentialsV4 = new V4Credentials(accessKeyId, v4SigningAccessKey, securityToken, region, signDate);
CredentialsProvider provider = new DefaultCredentialProvider(credentialsV4);
/**
* using {@link V4Credentials } initialize tableStore client
*/
SyncClient client = new SyncClient(endpoint, provider, instanceName, null, new ResourceManager(null, null));
// do something
client.listTable().getTableNames().forEach(System.out::println);
// shutdown tableStore client
client.shutdown();
}
}
}