rds 签名机制事例及补充说明

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 本篇主要是对官网rds签名机制的补充说明,以简单的代码实例来解释下每个步骤的含义,尽量会按照官方文档的描述举例

实为吾之愚见,望诸君酌之!闻过则喜,与君共勉

本篇主要是做下rds签名机制的补充,以简单的代码实例来解释下每个步骤的含义,尽量会按照官方文档的描述举例,关于签名机制的官方文档在这里:

https://help.aliyun.com/document_detail/26225.html?spm=5176.11065259.1996646101.searchclickresult.5f0d113dsmRQQp

一:先构造字符串

1.1 按照参数名称的字典顺序对请求中所有的请求参数(包括文档中描述的公共请求参数和给定了的请求接口的自定义参数,但不能包括公共请求参数中提到Signature参数本身)进行排序


例子:以DescribeDBInstances举例,该api需要的参数如下:SignatureVersionSignatureNonceSignatureMethodTimestampVersionActionAccessKeyIdFormatRegionId

按照要求,以字典顺序进行排序,结果如下:

[AccessKeyId, Action, Format, RegionId, SignatureMethod, SignatureNonce, SignatureVersion, Timestamp, Version]

这个顺序,就是在使用GET方法提交请求时的参数顺序,这些参数就是请求URL中的参数部分(即URL中“?”之后由“&”连接的部分)。

比如使用下面的方法排序:

String[] sortStr1 = new String[]{"Action","AccessKeyId", "RegionId", "SignatureVersion", "SignatureNonce", "SignatureMethod", "Timestamp", "Version", "Format"};

Arrays.sort(sortStr1);

System.out.println(Arrays.toString(sortStr1));

1.2 对每个请求参数名称和值进行编码。名称和值要使用UTF-8字符集进行URL编码,URL编码的编码规则是:
对于字符 A-Z、a-z、0-9以及字符(-)、(_)、(.)、(~)不编码。
对于其他字符编码成“%XY”的格式,其中XY是字符对应ASCII码的16进制表示。比如英文的双引号(”)对应的编码就是%22。
对于扩展的UTF-8字符,编码成“%XY%ZA…”的格式。
需要说明的是英文空格( )要被编码是%20,而不是加号(+)。
一般支持URL编码的库(比如Java中的java.net.URLEncoder)都是按照“application/x-www-form-urlencoded”的MIME类型的规则进行编码的。实现时可以直接使用这类方式进行编码,把编码后的字符串中加号(+)替换成%20、星号(*)替换成%2A、%7E替换回波浪号(~),即可得到上述规则描述的编码字符串。


例子:之前已经把参数做了排序,第二步是吧参数的名称和值使用utf-8字符集进行编码,按照说明,可以” 直接使用这类方式进行编码,把编码后的字符串中加号(+)替换成%20、星号(*)替换成%2A、%7E替换回波浪号(~),即可得到上述规则描述的编码字符串”,,名称和值分别如下:

AccessKeyId "LTAI0CeFaZcIg5cV"

Action "DescribeDBInstances"

Format "XML";

RegionId "cn-beijing";

SignatureVersion "1.0";

SignatureNonce UUID.randomUUID().toString();

SignatureMethod "HMAC-SHA1";

Timestamp Instant.now().toString().substring(0, 19);

Version "2014-08-15";

编码方式是:

java.net.URLEncoder.encode(key,"utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~")

则名称是:

java.net.URLEncoder.encode(“AccessKeyId”,"utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~")

java.net.URLEncoder.encode(“Action”,"utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~")

java.net.URLEncoder.encode(“Version”,"utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~")

值是:

java.net.URLEncoder.encode(“LTAI0CeFaZcIg5cV”,"utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~")

java.net.URLEncoder.encode(“DescribeDBInstances”,"utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~")

java.net.URLEncoder.encode(“2014-08-15”,"utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~")

最终编码完的名称和值如下:

AccessKeyId LTAI0CeFaZcIg5cV

Action DescribeDBInstances

Format XML

RegionId cn-beijing

SignatureMethod HMAC-SHA1

SignatureNonce 14d01fb6-0c62-48ae-b3f0-2b6f2b3c9428

SignatureVersion 1.0

Timestamp 2018-09-19T16%3A46%3A05

Version 2014-08-15

1.3对编码后的参数名称和值使用英文等号(=)进行连接。


例子:根据之前编码后的名称和值,用=连接后如下:

AccessKeyId= LTAI0CeFaZcIg5cV

Action=DescribeDBInstances

Format=XML

RegionId=cn-beijing

SignatureMethod=HMAC-SHA1

SignatureNonce= 14d01fb6-0c62-48ae-b3f0-2b6f2b3c9428

SignatureVersion=1.0

Timestamp= 2018-09-19T16%3A46%3A05

Version=2014-08-15

1.4再把英文等号连接得到的字符串按参数名称的字典顺序依次使用&符号连接,即得到规范化请求字符串


例子:按照第一步得到的参数顺序,用&拼接

AccessKeyId= LTAI0CeFaZcIg5cV &Action=DescribeDBInstances&Format=XML&RegionId=cn-beijing&SignatureMethod=HMAC-SHA1&SignatureNonce= 14d01fb6-0c62-48ae-b3f0-2b6f2b3c9428&SignatureVersion=1.0&Timestamp=2018-09-19T16%3A46%3A05&Version=2014-08-15

二,构造用于计算签名的字符串

 使用上一步构造的规范化字符串按照下面的规则构造用于计算签名的字符串:

StringToSign=

HTTPMethod + "&" +

percentEncode("/") + "&" +

percentEncode(CanonicalizedQueryString)

参数说明:

o    

§  HTTPMethod:提交请求用的HTTP方法,比GET

§  percentEncode(“/“):按照1.b中描述的URL编码规则对字符“/”进行编码得到的值,即“%2F”

§  percentEncode(CanonicalizedQueryString):对第1步中构造的规范化请求字符串按步骤1.ii中描述的URL编码规则编码后得到的字符串。


例子:

按照描述,StringToSign由这几部分组成,分别是HTTPMethod&percentEncode(“/“)&percentEncode(CanonicalizedQueryString),则这里:


HTTPMethod:使用get


&:保持不变


percentEncode("/"):java.net.URLEncoder.encode("/","utf-8"),%2F


percentEncode(CanonicalizedQueryString):

 java.net.URLEncoder.encode("AccessKeyId= LTAI0CeFaZcIg5cV &Action=DescribeDBInstances&Format=XML&RegionId=cn-beijing&SignatureMethod=HMAC-SHA1&SignatureNonce= 14d01fb6-0c62-48ae-b3f0-2b6f2b3c9428&SignatureVersion=1.0&Timestamp= 2018-09-19T16%3A46%3A05&Version=2014-08-15","utf-8"),:

AccessKeyId=LTAI0CeFaZcIg5cV&Action=DescribeDBInstances&Format=XML&RegionId=cn-beijing&SignatureMethod=HMAC-SHA1&SignatureNonce=14d01fb6-0c62-48ae-b3f0-2b6f2b3c9428&SignatureVersion=1.0&Timestamp=2018-09-19T16%3A46%3A05&Version=2014-08-15


最终,得到的StringToSign是:


GET&%2F&AccessKeyId%3DLTAI0CeFaZcIg5cV%26Action%3DDescribeDBInstances%26Format%3DXML%26RegionId%3Dcn-beijing%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D14d01fb6-0c62-48ae-b3f0-2b6f2b3c9428%26SignatureVersion%3D1.0%26Timestamp%3D2018-09-19T16%253A46%253A05%26Version%3D2014-08-15


  • :以上的步骤,可以写到一起来得出,比如下面的代码:

String Action="DescribeDBInstances";

String AccessKeyId="LTAI0CeFaZcIg5cV";

String Format="XML";

String RegionId="cn-beijing";

String SignatureVersion="1.0";

String SignatureNonce=UUID.randomUUID().toString();

String SignatureMethod="HMAC-SHA1";

String Timestamp=Instant.now().toString().substring(0, 19);

String Version="2014-08-15";

TreeMap<String, String> treeMap1 = new TreeMap<String, String>();

treeMap1.put("Action", Action);

treeMap1.put("AccessKeyId", AccessKeyId);

treeMap1.put("Format", Format);

treeMap1.put("RegionId", RegionId);

treeMap1.put("SignatureVersion", SignatureVersion);

treeMap1.put("SignatureNonce", SignatureNonce);

treeMap1.put("SignatureMethod", SignatureMethod);

treeMap1.put("Timestamp", Timestamp);

treeMap1.put("Version", Version);

Iterator iter=treeMap1.entrySet().iterator();

StringBuffer sb = new StringBuffer();

while(iter.hasNext()){

//System.out.println(iter.hasNext());

@SuppressWarnings("rawtypes")

Map.Entry entry=(Map.Entry) iter.next();

String key=entry.getKey().toString();

String value=entry.getValue().toString();

System.out.println(java.net.URLEncoder.encode(key,"utf-8"));

System.out.println(java.net.URLEncoder.encode(key,"utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~")+"="+java.net.URLEncoder.encode(value,"utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~"));

sb.append(java.net.URLEncoder.encode(key,"utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~")+"="+java.net.URLEncoder.encode(value,"utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~")+"&");

}

String sts=java.net.URLEncoder.encode(sb.toString().substring(0, 238));

String StringToSign="GET"+"&"+"%2F"+"&"+sts;


三,计算hmac值

按照RFC2104的定义,使用上面的用于签名的字符串计算签名HMAC值。

注意计算签名时使用的Key就是用户持有的Access Key Secret并加上一个“&”字符(ASCII:38),使用的哈希算法是SHA1


例子:hmac-sha1的算法代码实现可以网上搜索,然后计算,以下为事例:

HmacSha1Signature hmac=new HmacSha1Signature();

byte[] Signature =hmac.calculateRFC2104HMAC(StringToSign," lpc2nHx6OUBbTlG7TviOc12XnWf9gO&");

注意,Access Key Secret后面要加一个&

四,计算签名值

按照Base64编码规则把上面的HMAC值编码成字符串,即得到签名值(Signature)。


例子:

String Signature_ Base64 = Base64.encodeBase64String(Signature);

得到:

DJG/5KS60WAHbhGuRPR60WH/2BQ=

五,编码签名

将得到的签名值作为Signature参数添加到请求参数中,即完成对请求签名的过程。

说明:得到的签名值在作为最后的请求参数值提交给RDS服务器的时候,要和其他参数一样,按照RFC3986的规则进行URL编码)。


例子:第四步得到的签名是jVBrEWqwk61+1N7n8BF7uszqDiU=,则参数就是: Signature= DJG/5KS60WAHbhGuRPR60WH/2BQ=

编码后是: Signature=DJG%2F5KS60WAHbhGuRPR60WH%2F2BQ%3D


至此签名已经拿到,则添加到请求url

http://rds.aliyuncs.com/?AccessKeyId=LTAI0CeFaZcIg5cV&Action=DescribeDBInstances&Format=XML&RegionId=cn-beijing&SignatureMethod=HMAC-SHA1&SignatureNonce=14d01fb6-0c62-48ae-b3f0-2b6f2b3c9428&SignatureVersion=1.0&Timestamp=2018-09-19T16%3A46%3A05&Version=2014-08-15&&Signature=DJG%2F5KS60WAHbhGuRPR60WH%2F2BQ%3D

得到如下请求结果:

7deb17a2b1eeed9369fca13a404053e0d1a2e876



相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
XML 算法 关系型数据库
rds 签名机制事例及补充说明
本篇主要是对官网rds签名机制的补充说明,以简单的代码实例来解释下每个步骤的含义,尽量会按照官方文档的描述举例
rds 签名机制事例及补充说明
|
1月前
|
存储 SQL 关系型数据库
Mysql学习笔记(二):数据库命令行代码总结
这篇文章是关于MySQL数据库命令行操作的总结,包括登录、退出、查看时间与版本、数据库和数据表的基本操作(如创建、删除、查看)、数据的增删改查等。它还涉及了如何通过SQL语句进行条件查询、模糊查询、范围查询和限制查询,以及如何进行表结构的修改。这些内容对于初学者来说非常实用,是学习MySQL数据库管理的基础。
128 6
|
8天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
23 1
|
10天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
25 4
|
1月前
|
存储 关系型数据库 MySQL
Mysql(4)—数据库索引
数据库索引是用于提高数据检索效率的数据结构,类似于书籍中的索引。它允许用户快速找到数据,而无需扫描整个表。MySQL中的索引可以显著提升查询速度,使数据库操作更加高效。索引的发展经历了从无索引、简单索引到B-树、哈希索引、位图索引、全文索引等多个阶段。
61 3
Mysql(4)—数据库索引
|
1月前
|
SQL Ubuntu 关系型数据库
Mysql学习笔记(一):数据库详细介绍以及Navicat简单使用
本文为MySQL学习笔记,介绍了数据库的基本概念,包括行、列、主键等,并解释了C/S和B/S架构以及SQL语言的分类。接着,指导如何在Windows和Ubuntu系统上安装MySQL,并提供了启动、停止和重启服务的命令。文章还涵盖了Navicat的使用,包括安装、登录和新建表格等步骤。最后,介绍了MySQL中的数据类型和字段约束,如主键、外键、非空和唯一等。
70 3
Mysql学习笔记(一):数据库详细介绍以及Navicat简单使用
|
17天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
84 1
|
19天前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。同时,文章还对比了编译源码安装与使用 RPM 包安装的优缺点,帮助读者根据需求选择最合适的方法。通过具体案例,展示了编译源码安装的灵活性和定制性。
61 2
|
22天前
|
存储 关系型数据库 MySQL
MySQL vs. PostgreSQL:选择适合你的开源数据库
在众多开源数据库中,MySQL和PostgreSQL无疑是最受欢迎的两个。它们都有着强大的功能、广泛的社区支持和丰富的生态系统。然而,它们在设计理念、性能特点、功能特性等方面存在着显著的差异。本文将从这三个方面对MySQL和PostgreSQL进行比较,以帮助您选择更适合您需求的开源数据库。
89 4
|
5天前
|
运维 关系型数据库 MySQL
安装MySQL8数据库
本文介绍了MySQL的不同版本及其特点,并详细描述了如何通过Yum源安装MySQL 8.4社区版,包括配置Yum源、安装MySQL、启动服务、设置开机自启动、修改root用户密码以及设置远程登录等步骤。最后还提供了测试连接的方法。适用于初学者和运维人员。
38 0