首页> 搜索结果页
"php string操作" 检索
共 59 条结果
懂php和java的进来,求教一个问题 报错
" 1 和别的公司对接业务,对方java,我是php。2 双方把把数据先DES加密,再base64加密。进行传输3 对方发了一个java的加密解密,我应该照着做一个php的。但看不懂java代码。4 求大神能忙,万谢。 package com.ab.mediation.util; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; /** * 对外接口数据加密/解密类 * @author xin * */ public class DesUtil { private final static String DES = "DES"; public static void main(String[] args) throws Exception { String tDoc = "";// 请求报文 String encoding = "GBK"; // 将函数参数赋给本地参数 String path = "/Users/jieliu/Code/a.txt"; // String path = "F:\\testxml\\requestAppPolInp881.xml"; String path1 = path; // 初始化文件对象f File f = new File(path1); // 初始化读数据流对象reader InputStreamReader reader = new InputStreamReader(new FileInputStream( path1), encoding); // 根据f文件长度初始化字符串数据c[] char c[] = new char[(int) (f.length())]; // 取到字符串长度,并将文件f内容写入数组c int length = reader.read(c); // 逐字节将字符串数组c[],赋给变量tDoc for (int i = 0; i < length; i++) { tDoc = tDoc + c[i]; } String key = "12dc293d43db3b237849"; System.out.println(encrypt(tDoc, key)); System.out.println(decrypt(encrypt(tDoc, key), key)); } /** * Description 根据键值进行加密 * * @param data * @param key * 加密键byte数组 * @return * @throws Exception */ public static String encrypt(String data, String key) throws Exception { byte[] bt = encrypt(data.getBytes(), key.getBytes()); String strs = new BASE64Encoder().encode(bt); return strs; } /** * 指定字符编码方式并加密 * @param data * @param key * @param encoding * @return * @throws Exception */ public static String encrypt(String data, String key, String encoding) throws Exception { byte[] bt = encrypt(data.getBytes(encoding), key.getBytes()); String strs = new BASE64Encoder().encode(bt); return strs; } /** * Description 根据键值进行解密 * * @param data * @param key * 加密键byte数组 * @return * @throws IOException * @throws Exception */ public static String decrypt(String data, String key) throws IOException, Exception { if (data == null) return null; BASE64Decoder decoder = new BASE64Decoder(); byte[] buf = decoder.decodeBuffer(data); byte[] bt = decrypt(buf, key.getBytes()); return new String(bt); } /** * 根据键值解密并返回指定编码方式字符串 * @param data * @param key * @param encoding * @return * @throws IOException * @throws Exception */ public static String decrypt(String data, String key, String encoding) throws IOException, Exception { if (data == null) return null; BASE64Decoder decoder = new BASE64Decoder(); byte[] buf = decoder.decodeBuffer(data); byte[] bt = decrypt(buf, key.getBytes()); return new String(bt, encoding); } /** * Description 根据键值进行加密 * * @param data * @param key * 加密键byte数组 * @return * @throws Exception */ private static byte[] encrypt(byte[] data, byte[] key) throws Exception { // 生成一个可信任的随机数源 SecureRandom sr = new SecureRandom(); // 从原始密钥数据创建DESKeySpec对象 DESKeySpec dks = new DESKeySpec(key); // 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey securekey = keyFactory.generateSecret(dks); // Cipher对象实际完成加密操作 Cipher cipher = Cipher.getInstance(DES); // 用密钥初始化Cipher对象 cipher.init(Cipher.ENCRYPT_MODE, securekey, sr); return cipher.doFinal(data); } /** * Description 根据键值进行解密 * * @param data * @param key * 加密键byte数组 * @return * @throws Exception */ private static byte[] decrypt(byte[] data, byte[] key) throws Exception { // 生成一个可信任的随机数源 SecureRandom sr = new SecureRandom(); // 从原始密钥数据创建DESKeySpec对象 DESKeySpec dks = new DESKeySpec(key); // 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES); SecretKey securekey = keyFactory.generateSecret(dks); // Cipher对象实际完成解密操作 Cipher cipher = Cipher.getInstance(DES); // 用密钥初始化Cipher对象 cipher.init(Cipher.DECRYPT_MODE, securekey, sr); return cipher.doFinal(data); } } " ![image.png](https://ucc.alicdn.com/pic/developer-ecology/3e1a6c3761a54afba05b93ba2793612c.png)
问答
Java · PHP
2020-05-26
懂JAVA&PHP的进,求一JAVA数据加密类的PHP版本。 报错
" 跟人合作搞个Android App,我负责服务器端 用的是PHP, 手机端和服务器端之间的数据传输有加密, 他手机端用的是这个JAVA的数据加密类, 求相对应的PHP版本 数据加密类。 <code class=""lang-java"">package com.ssh.util; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.security.Key; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESedeKeySpec; import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; /** * DESede对称加密算法演示 * * @author zolly * */ public class DESedeCoder { /** * 密钥算法 * */ public static final String KEY_ALGORITHM = "DESede"; /** * 加密/解密算法/工作模式/填充方式 * */ public static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding"; /** * * 生成密钥 * * @return byte[] 二进制密钥 * */ public static byte[] initkey() throws Exception { // 实例化密钥生成器 KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM); // 初始化密钥生成器 kg.init(168); // 生成密钥 SecretKey secretKey = kg.generateKey(); // 获取二进制密钥编码形式 byte[] key = secretKey.getEncoded(); BufferedOutputStream keystream = new BufferedOutputStream(new FileOutputStream("DESedeKey.dat")); keystream.write(key, 0, key.length); keystream.flush(); keystream.close(); return key; } /** * 转换密钥 * * @param key * 二进制密钥 * @return Key 密钥 * */ public static Key toKey(byte[] key) throws Exception { // 实例化Des密钥 DESedeKeySpec dks = new DESedeKeySpec(key); // 实例化密钥工厂 SecretKeyFactory keyFactory = SecretKeyFactory .getInstance(KEY_ALGORITHM); // 生成密钥 SecretKey secretKey = keyFactory.generateSecret(dks); return secretKey; } /** * 加密数据 * * @param data * 待加密数据 * @param key * 密钥 * @return byte[] 加密后的数据 * */ public static byte[] encrypt(byte[] data, byte[] key) throws Exception { // 还原密钥 Key k = toKey(key); // 实例化 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); // 初始化,设置为加密模式 cipher.init(Cipher.ENCRYPT_MODE, k); // 执行操作 return cipher.doFinal(data); } /** * 解密数据 * * @param data * 待解密数据 * @param key * 密钥 * @return byte[] 解密后的数据 * */ public static byte[] decrypt(byte[] data, byte[] key) throws Exception { // 欢迎密钥 Key k = toKey(key); // 实例化 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); // 初始化,设置为解密模式 cipher.init(Cipher.DECRYPT_MODE, k); // 执行操作 return cipher.doFinal(data); } /** * 加密字符串 * @param data * @return */ public static String encode(String str,String screatKey){ String result = ""; byte[] data = DESedeCoder.encrypt(str.getBytes(), screatKey.getBytes()); result = Base64.encode(data); return result; } /** * 解密字符串 * @param str * @return */ public static String decode(String str,String screatKey){ String result = ""; try { byte[] data = Base64.decode(str); data = DESedeCoder.decrypt(data, screatKey.getBytes()); result = new String(data); } catch (Exception e) { e.printStackTrace(); } return result; } /** * 进行加解密的测试 * * @throws Exception */ public static void main(String[] args) throws Exception { String key = "2C7dDYBy20mmKy3391xivikz"; String str = "hello world~"; System.out.println("Key:"+key); System.out.println("原文:" + str); //加密 String value = encode(str,key); System.out.println("加密后:" + value); System.out.println("解密后:" + decode(value,key)); } } " ![image.png](https://ucc.alicdn.com/pic/developer-ecology/91bd2557f6474907a0b2070f467909f6.png)
问答
Java · PHP · 数据安全/隐私保护
2020-05-26
PHP mysql的操作,为什么要返回一个字符串数组?
http://www.php.net/manual/zh/mysqli-result.fetch-array.php返回值Returns an array of strings that corresponds to the fetched row or NULL if there are no more rows in resultset.这里返回的是an array of strings,无论表中数据是整数还是浮点数,都是返回string类型的。为什么要这样设计?这个带来的坏处就是JSON化的时候会都是string类型,导致数据不准确,必须手动去转化数据。
问答
JSON · 关系型数据库 · MySQL · PHP · 数据格式
2016-06-17
API 签名机制
阿里云产品服务会对每个访问请求进行身份验证,所以无论您使用 HTTP 还是 HTTPS 协议提交请求,都需要在请求中包含签名(Signature)信息。 签名需要您在控制台 Access Key 管理页面获得 Access Key ID 和 Access Key Secret,进行对称加密来验证请求的发送者身份。其中,Access KeyID 用于标识访问者身份;Access Key Secret 是用于加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密。 注意:阿里云提供了 Python、Java、PHP 和 C# 等语言的 SDK 及第三方 SDK,可以免去您对签名算法进行编码的麻烦。您可以从 这里 了解更多阿里云 SDK 的信息。 签名操作 您在访问时,需要按照下面的方法对请求进行签名处理。 构造规范化的请求字符串(Canonicalized Query String)。按参数名进行排序。 按照参数名称的字典顺序对请求中所有的请求参数进行排序,包括“公共请求参数”(不包括 Signature 参数)和接口的自定义参数。 注意:当使用 GET 方法提交请求时,这些参数就是请求 URI 中的参数部分(即 URI 中“?”之后由“&”连接的部分)。 对参数名称和参数值进行 URL 编码。 名称和值要使用 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 替换回波浪号(~),即可得到上述规则描述的编码字符串。 对编码后的参数名称和值使用英文等号(=)进行连接。 按参数名称的字典顺序,把英文等号连接得到字符串依次使用 & 符号连接,即得到规范化请求字符串。 构造被签名字符串。 基于步骤 1 得到的规范化字符串构造用于计算签名的字符串,可参考如下规则: StringToSign=     HTTPMethod + “&” +     percentEncode(“/”) + ”&” +      percentEncode(CanonicalizedQueryString) 其中: HTTPMethod 是提交请求用的 HTTP 方法,比如 GET。percentEncode(“/”) 是按照步骤 1.i 中描述的 URL 编码规则对字符 “/” 进行编码得到的值,即 %2F。 percentEncode(CanonicalizedQueryString) 是对步骤 1 中构造的规范化请求字符串按步骤 1.ii 中描述的 URL 编码规则编码后得到的字符串。 计算 HMAC 值。 按照 RFC2104 的定义,使用步骤 2 得到的字符串计算签名 HMAC 值。 注意:计算签名时使用的 Key 就是您持有的 Access Key Secret 并加上一个 “&” 字符(ASCII:38),使用的哈希算法是 SHA1。 计算签名值。 按照 Base64 编码规则 把步骤 3 中的 HMAC 值编码成字符串,即得到签名值(Signature)。 添加签名。 将得到的签名值作为 Signature 参数添加到请求参数中,即完成对请求签名的过程。 注意:得到的签名值在作为最后的请求参数值提交给服务器时,要和其它参数一样,按照 RFC3986 的规则进行 URL 编码。 示例 以 DescribeRegions 为例,假设使用的 Access Key Id 为 testid, Access Key Secret 为 testsecret。 那么签名前的请求 URL 为:    http://ecs.aliyuncs.com/?TimeStamp=2016-02-23T12:46:24Z&Format=XML&AccessKeyId=testid&Action=DescribeRegions&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&SignatureVersion=1.0 计算得到的待签名字符串 StringToSign 为:    GET&%2F&AccessKeyId%3Dtestid&Action%3DDescribeRegions&Format%3DXML&SignatureMethod%3DHMAC-SHA1&SignatureNonce%3D3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&SignatureVersion%3D1.0&TimeStamp%3D2016-02-23T12%253A46%253A24Z&Version%3D2014-05-26 因为 Access Key Secret 为 testsecret,所以用于计算 HMAC 的 Key 为 testsecret&,计算得到的签名值为:    CT9X0VtwR86fNWSnsc6v8YGOjuE= 将签名作为 Signature 参数加入到 URL 请求中,最后得到的 URL 为:    http://ecs.aliyuncs.com/?SignatureVersion=1.0&Action=DescribeRegions&Format=XML&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&AccessKeyId=testid&Signature=CT9X0VtwR86fNWSnsc6v8YGOjuE%3D&SignatureMethod=HMAC-SHA1&TimeStamp=2016-02-23T12%3A46%3A24Z Java 示例代码 本示例不需要依赖第三方的库包,可以直接使用。签名步骤如下所示。 构造规范化的请求字符串(排序及 URL 编码)。 public static Map<String, String> splitQueryString(String url)         throws URISyntaxException, UnsupportedEncodingException {     URI uri = new URI(url);     String query = uri.getQuery();     final String[] pairs = query.split("&");     TreeMap<String, String> queryMap = new TreeMap<String, String>();     for (String pair : pairs) {         final int idx = pair.indexOf("=");         final String key = idx > 0 ? pair.substring(0, idx) : pair;         if (!queryMap.containsKey(key)) {             queryMap.put(key, URLDecoder.decode(pair.substring(idx + 1),                     CHARSET_UTF8));         }     }     return queryMap; }/** 对参数名称和参数值进行URL编码**/ public static String generate(String method, Map<String, String> parameter,                               String accessKeySecret) throws Exception {     String signString = generateSignString(method, parameter);     System.out.println("signString---" + signString);     byte[] signBytes = hmacSHA1Signature(accessKeySecret + "&", signString);     String signature = newStringByBase64(signBytes);     System.out.println("signature---" + signature);     if ("POST".equals(method))         return signature;     return URLEncoder.encode(signature, "UTF-8"); } 构造成待签名的字符串。 public static String generateSignString(String httpMethod,                                         Map<String, String> parameter) throws IOException {     TreeMap<String, String> sortParameter = new TreeMap<String, String>();     sortParameter.putAll(parameter);     String canonicalizedQueryString = UrlUtil.generateQueryString(             sortParameter, true);     if (null == httpMethod) {         throw new RuntimeException("httpMethod can not be empty");     }     /** 构造待签名的字符串* */     StringBuilder stringToSign = new StringBuilder();     stringToSign.append(httpMethod).append(SEPARATOR);     stringToSign.append(percentEncode("/")).append(SEPARATOR);     stringToSign.append(percentEncode(canonicalizedQueryString));     return stringToSign.toString(); } 计算待签名字符串的 HMAC 值。 public static byte[] hmacSHA1Signature(String secret, String baseString)         throws Exception {     if (isEmpty(secret)) {         throw new IOException("secret can not be empty");     }     if (isEmpty(baseString)) {         return null;     }     Mac mac = Mac.getInstance("HmacSHA1");     SecretKeySpec keySpec = new SecretKeySpec(             secret.getBytes(CHARSET_UTF8), ALGORITHM);     mac.init(keySpec);     return mac.doFinal(baseString.getBytes(CHARSET_UTF8)); } private static boolean isEmpty(String str) {    return (str == null || str.length() == 0); } 按照 Base64 编码规则编码成字符串,获取签名值。 public static String newStringByBase64(byte[] bytes)         throws UnsupportedEncodingException {     if (bytes == null || bytes.length == 0) {         return null;     }     return new String(new BASE64Encoder().encode(bytes)); } public static String composeStringToSign(Map<String, String> queries) {     String[] sortedKeys = (String[]) queries.keySet()             .toArray(new String[0]);     Arrays.sort(sortedKeys);     StringBuilder canonicalizedQueryString = new StringBuilder();     for (String key : sortedKeys) {            canonicalizedQueryString.append("&").append(percentEncode(key))                 .append("=")                 .append(percentEncode((String) queries.get(key)));     }     StringBuilder stringToSign = new StringBuilder();     stringToSign.append("GET");     stringToSign.append("&");     stringToSign.append(percentEncode("/"));     stringToSign.append("&");        stringToSign.append(percentEncode(canonicalizedQueryString.toString()             .substring(1)));     return stringToSign.toString(); } public static String percentEncode(String value) {     try {         return value == null ? null : URLEncoder                 .encode(value, CHARSET_UTF8).replace("+", "%20")                 .replace("*", "%2A").replace("%7E", "~");     } catch (Exception e) {     }     return ""; } /**  * get SignatureNonce  ** */ public static String getUniqueNonce() {     UUID uuid = UUID.randomUUID();     return uuid.toString(); } /**  * get timestamp  **/ public static String getISO8601Time() {     Date nowDate = new Date();     SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");     df.setTimeZone(new SimpleTimeZone(0, "GMT"));     return df.format(nowDate); } 添加签名。 public static String composeUrl(String endpoint, Map<String, String> queries)         throws UnsupportedEncodingException {     Map<String, String> mapQueries = queries;     StringBuilder urlBuilder = new StringBuilder("");     urlBuilder.append("http");     urlBuilder.append("://").append(endpoint);     if (-1 == urlBuilder.indexOf("?")) {         urlBuilder.append("/?");     }     urlBuilder.append(concatQueryString(mapQueries));     return urlBuilder.toString(); } public static String concatQueryString(Map<String, String> parameters)         throws UnsupportedEncodingException {     if (null == parameters) {         return null;     }     StringBuilder urlBuilder = new StringBuilder("");     for (Map.Entry<String, String> entry : parameters.entrySet()) {         String key = (String) entry.getKey();         String val = (String) entry.getValue();         urlBuilder.append(encode(key));         if (val != null) {             urlBuilder.append("=").append(encode(val));         }         urlBuilder.append("&");     }     int strIndex = urlBuilder.length();     if (parameters.size() > 0) {         urlBuilder.deleteCharAt(strIndex - 1);     }     return urlBuilder.toString(); } public static String encode(String value)         throws UnsupportedEncodingException {     return URLEncoder.encode(value, "UTF-8"); }} API 调用示例 示例 1 /* * Demo_01: Build a immutable signature instance and print out; * The Signature's toString() function will invoke signature's get() function. */out("output: " +        Signature.newBuilder()            .method(The.HTTP.GET.method())            .url(URL)            .secret(The.API.secret())            .build()); 示例 2 /* * Demo_02: Build a real signature and compose a request url to invoke DescribeRegions api call; */对一个真实的 API URL 进行签名final String ACTION = "DescribeRegions";final String API_URL = The.API.build(ACTION);out(httpGet(Signature.newBuilder()                .method(The.HTTP.GET.method())                .url(API_URL)                .secret(The.API.secret())                .build()                .compose())); 为了方便您快速使用签名机制,您可以在 这里 下载完整的示例代码。 注意:您需要将 ACCESS 和 SECRET 替换为您的 Access Key ID 和 Access Key Secret。
问答
算法 · Java · API · PHP · 开发工具 · C# · 数据安全/隐私保护 · Python
2017-10-18
API 签名机制是什么?
阿里云产品服务会对每个访问请求进行身份验证,所以无论您使用 HTTP 还是 HTTPS协议提交请求,都需要在请求中包含签名(Signature)信息。 签名需要您在控制台 AccessKey 管理 页面获得 Access Key ID 和 Access Key Secret,进行对称加密来验证请求的发送者身份。其中,AccessKey ID 用于标识访问者身份;Access Key Secret 是用于加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密。 注意:阿里云提供了 Python、Java、PHP和 C#等语言的 SDK 及第三方 SDK,可以免去您对签名算法进行编码的麻烦。您可以从 这里了解更多阿里云 SDK 的信息。 签名操作 您在访问时,需要按照下面的方法对请求进行签名处理。 构造规范化的请求字符串(Canonicalized Query String)。按参数名进行排序。 按照参数名称的字典顺序对请求中所有的请求参数进行排序,包括“公共请求参数”(不包括 Signature参数)和接口的自定义参数。 注意:当使用 GET 方法提交请求时,这些参数就是请求 URI 中的参数部分(即 URI中“?”之后由“&”连接的部分)。 对参数名称和参数值进行 URL 编码。 名称和值要使用 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 替换回波浪号(~),即可得到上述规则描述的编码字符串。 对编码后的参数名称和值使用英文等号(=)进行连接。 按参数名称的字典顺序,把英文等号连接得到字符串依次使用 &符号连接,即得到规范化请求字符串。 构造被签名字符串。 基于步骤 1 得到的规范化字符串构造用于计算签名的字符串,可参考如下规则: StringToSign=     HTTPMethod + “&” +     percentEncode(“/”) + ”&” +      percentEncode(CanonicalizedQueryString) 其中: HTTPMethod 是提交请求用的 HTTP 方法,比如 GET。percentEncode(“/”) 是按照步骤 1.i 中描述的 URL 编码规则对字符 “/” 进行编码得到的值,即%2F。 percentEncode(CanonicalizedQueryString) 是对步骤 1 中构造的规范化请求字符串按步骤1.ii 中描述的 URL 编码规则编码后得到的字符串。 计算 HMAC 值。 按照 RFC2104的定义,使用步骤 2 得到的字符串计算签名 HMAC 值。 注意:计算签名时使用的 Key 就是您持有的 Access Key Secret 并加上一个“&” 字符(ASCII:38),使用的哈希算法是 SHA1。 计算签名值。 按照 Base64编码规则 把步骤 3 中的 HMAC 值编码成字符串,即得到签名值(Signature)。 添加签名。 将得到的签名值作为 Signature 参数添加到请求参数中,即完成对请求签名的过程。 注意:得到的签名值在作为最后的请求参数值提交给服务器时,要和其它参数一样,按照 RFC3986 的规则进行 URL编码。 示例 以 DescribeRegions 为例,假设使用的 Access Key Id 为 testid,Access Key Secret 为 testsecret。 那么签名前的请求 URL 为:    http://ecs.aliyuncs.com/?TimeStamp=2016-02-23T12:46:24Z&Format=XML&AccessKeyId=testid&Action=DescribeRegions&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&SignatureVersion=1.0 计算得到的待签名字符串 StringToSign 为:    GET&%2F&AccessKeyId%3Dtestid&Action%3DDescribeRegions&Format%3DXML&SignatureMethod%3DHMAC-SHA1&SignatureNonce%3D3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&SignatureVersion%3D1.0&TimeStamp%3D2016-02-23T12%253A46%253A24Z&Version%3D2014-05-26 因为 Access Key Secret 为 testsecret,所以用于计算 HMAC 的 Key为 testsecret&,计算得到的签名值为:    CT9X0VtwR86fNWSnsc6v8YGOjuE= 将签名作为 Signature 参数加入到 URL 请求中,最后得到的 URL 为:    http://ecs.aliyuncs.com/?SignatureVersion=1.0&Action=DescribeRegions&Format=XML&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&AccessKeyId=testid&Signature=CT9X0VtwR86fNWSnsc6v8YGOjuE%3D&SignatureMethod=HMAC-SHA1&TimeStamp=2016-02-23T12%3A46%3A24Z Java 示例代码 本示例不需要依赖第三方的库包,可以直接使用。签名步骤如下所示。 构造规范化的请求字符串(排序及 URL 编码)。 public static Map<String, String> splitQueryString(String url)         throws URISyntaxException, UnsupportedEncodingException {     URI uri = new URI(url);     String query = uri.getQuery();     final String[] pairs = query.split("&");     TreeMap<String, String> queryMap = new TreeMap<String, String>();     for (String pair : pairs) {         final int idx = pair.indexOf("=");         final String key = idx > 0 ? pair.substring(0, idx) : pair;         if (!queryMap.containsKey(key)) {             queryMap.put(key, URLDecoder.decode(pair.substring(idx + 1),                     CHARSET_UTF8));         }     }     return queryMap; }/** 对参数名称和参数值进行URL编码**/ public static String generate(String method, Map<String, String> parameter,                               String accessKeySecret) throws Exception {     String signString = generateSignString(method, parameter);     System.out.println("signString---" + signString);     byte[] signBytes = hmacSHA1Signature(accessKeySecret + "&", signString);     String signature = newStringByBase64(signBytes);     System.out.println("signature---" + signature);     if ("POST".equals(method))         return signature;     return URLEncoder.encode(signature, "UTF-8"); } 构造成待签名的字符串。 public static String generateSignString(String httpMethod,                                         Map<String, String> parameter) throws IOException {     TreeMap<String, String> sortParameter = new TreeMap<String, String>();     sortParameter.putAll(parameter);     String canonicalizedQueryString = UrlUtil.generateQueryString(             sortParameter, true);     if (null == httpMethod) {         throw new RuntimeException("httpMethod can not be empty");     }     /** 构造待签名的字符串* */     StringBuilder stringToSign = new StringBuilder();     stringToSign.append(httpMethod).append(SEPARATOR);     stringToSign.append(percentEncode("/")).append(SEPARATOR);     stringToSign.append(percentEncode(canonicalizedQueryString));     return stringToSign.toString(); } 计算待签名字符串的 HMAC 值。 public static byte[] hmacSHA1Signature(String secret, String baseString)         throws Exception {     if (isEmpty(secret)) {         throw new IOException("secret can not be empty");     }     if (isEmpty(baseString)) {         return null;     }     Mac mac = Mac.getInstance("HmacSHA1");     SecretKeySpec keySpec = new SecretKeySpec(             secret.getBytes(CHARSET_UTF8), ALGORITHM);     mac.init(keySpec);     return mac.doFinal(baseString.getBytes(CHARSET_UTF8)); } private static boolean isEmpty(String str) {    return (str == null || str.length() == 0); } 按照 Base64 编码规则编码成字符串,获取签名值。 public static String newStringByBase64(byte[] bytes)         throws UnsupportedEncodingException {     if (bytes == null || bytes.length == 0) {         return null;     }     return new String(new BASE64Encoder().encode(bytes)); } public static String composeStringToSign(Map<String, String> queries) {     String[] sortedKeys = (String[]) queries.keySet()             .toArray(new String[0]);     Arrays.sort(sortedKeys);     StringBuilder canonicalizedQueryString = new StringBuilder();     for (String key : sortedKeys) {            canonicalizedQueryString.append("&").append(percentEncode(key))                 .append("=")                 .append(percentEncode((String) queries.get(key)));     }     StringBuilder stringToSign = new StringBuilder();     stringToSign.append("GET");     stringToSign.append("&");     stringToSign.append(percentEncode("/"));     stringToSign.append("&");        stringToSign.append(percentEncode(canonicalizedQueryString.toString()             .substring(1)));     return stringToSign.toString(); } public static String percentEncode(String value) {     try {         return value == null ? null : URLEncoder                 .encode(value, CHARSET_UTF8).replace("+", "%20")                 .replace("*", "%2A").replace("%7E", "~");     } catch (Exception e) {     }     return ""; } /**  * get SignatureNonce  ** */ public static String getUniqueNonce() {     UUID uuid = UUID.randomUUID();     return uuid.toString(); } /**  * get timestamp  **/ public static String getISO8601Time() {     Date nowDate = new Date();     SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");     df.setTimeZone(new SimpleTimeZone(0, "GMT"));     return df.format(nowDate); } 添加签名。 public static String composeUrl(String endpoint, Map<String, String> queries)         throws UnsupportedEncodingException {     Map<String, String> mapQueries = queries;     StringBuilder urlBuilder = new StringBuilder("");     urlBuilder.append("http");     urlBuilder.append("://").append(endpoint);     if (-1 == urlBuilder.indexOf("?")) {         urlBuilder.append("/?");     }     urlBuilder.append(concatQueryString(mapQueries));     return urlBuilder.toString(); } public static String concatQueryString(Map<String, String> parameters)         throws UnsupportedEncodingException {     if (null == parameters) {         return null;     }     StringBuilder urlBuilder = new StringBuilder("");     for (Map.Entry<String, String> entry : parameters.entrySet()) {         String key = (String) entry.getKey();         String val = (String) entry.getValue();         urlBuilder.append(encode(key));         if (val != null) {             urlBuilder.append("=").append(encode(val));         }         urlBuilder.append("&");     }     int strIndex = urlBuilder.length();     if (parameters.size() > 0) {         urlBuilder.deleteCharAt(strIndex - 1);     }     return urlBuilder.toString(); } public static String encode(String value)         throws UnsupportedEncodingException {     return URLEncoder.encode(value, "UTF-8"); }} API 调用示例 示例 1 /* * Demo_01: Build a immutable signature instance and print out; * The Signature's toString() function will invoke signature's get() function. */out("output: " +        Signature.newBuilder()            .method(The.HTTP.GET.method())            .url(URL)            .secret(The.API.secret())            .build()); 示例 2 /* * Demo_02: Build a real signature and compose a request url to invoke DescribeRegions api call; */对一个真实的 API URL 进行签名final String ACTION = "DescribeRegions";final String API_URL = The.API.build(ACTION);out(httpGet(Signature.newBuilder()                .method(The.HTTP.GET.method())                .url(API_URL)                .secret(The.API.secret())                .build()                .compose())); 为了方便您快速使用签名机制,您可以在 这里下载完整的示例代码。 注意:您需要将 ACCESS 和 SECRET 替换为您的 Access Key ID 和 Access KeySecret。
问答
算法 · Java · API · PHP · 开发工具 · C# · 数据安全/隐私保护 · Python
2017-10-31
API 签名机制是什么?
阿里云产品服务会对每个访问请求进行身份验证,所以无论您使用 HTTP 还是 HTTPS协议提交请求,都需要在请求中包含签名(Signature)信息。 签名需要您在控制台 AccessKey 管理 页面获得 Access Key ID 和 Access Key Secret,进行对称加密来验证请求的发送者身份。其中,AccessKey ID 用于标识访问者身份;Access Key Secret 是用于加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密。 注意:阿里云提供了 Python、Java、PHP和 C#等语言的 SDK 及第三方 SDK,可以免去您对签名算法进行编码的麻烦。您可以从 这里了解更多阿里云 SDK 的信息。 [font='iconfont'] 签名操作 您在访问时,需要按照下面的方法对请求进行签名处理。 构造规范化的请求字符串(Canonicalized Query String)。按参数名进行排序。 按照参数名称的字典顺序对请求中所有的请求参数进行排序,包括“公共请求参数”(不包括 Signature参数)和接口的自定义参数。 注意:当使用 GET 方法提交请求时,这些参数就是请求 URI 中的参数部分(即 URI中“?”之后由“&”连接的部分)。 对参数名称和参数值进行 URL 编码。 名称和值要使用 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 替换回波浪号(~),即可得到上述规则描述的编码字符串。 对编码后的参数名称和值使用英文等号(=)进行连接。 按参数名称的字典顺序,把英文等号连接得到字符串依次使用 &符号连接,即得到规范化请求字符串。 构造被签名字符串。 基于步骤 1 得到的规范化字符串构造用于计算签名的字符串,可参考如下规则: StringToSign=     HTTPMethod + “&” +     percentEncode(“/”) + ”&” +      percentEncode(CanonicalizedQueryString) 其中: HTTPMethod 是提交请求用的 HTTP 方法,比如 GET。percentEncode(“/”) 是按照步骤 1.i 中描述的 URL 编码规则对字符 “/” 进行编码得到的值,即%2F。 percentEncode(CanonicalizedQueryString) 是对步骤 1 中构造的规范化请求字符串按步骤1.ii 中描述的 URL 编码规则编码后得到的字符串。 计算 HMAC 值。 按照 RFC2104的定义,使用步骤 2 得到的字符串计算签名 HMAC 值。 注意:计算签名时使用的 Key 就是您持有的 Access Key Secret 并加上一个“&” 字符(ASCII:38),使用的哈希算法是 SHA1。 计算签名值。 按照 Base64编码规则 把步骤 3 中的 HMAC 值编码成字符串,即得到签名值(Signature)。 添加签名。 将得到的签名值作为 Signature 参数添加到请求参数中,即完成对请求签名的过程。 注意:得到的签名值在作为最后的请求参数值提交给服务器时,要和其它参数一样,按照 RFC3986 的规则进行 URL编码。 [font='iconfont'] 示例 以 DescribeRegions 为例,假设使用的 Access Key Id 为 testid,Access Key Secret 为 testsecret。 那么签名前的请求 URL 为:    http://ecs.aliyuncs.com/?TimeStamp=2016-02-23T12:46:24Z&Format=XML&AccessKeyId=testid&Action=DescribeRegions&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&SignatureVersion=1.0 计算得到的待签名字符串 StringToSign 为:    GET&%2F&AccessKeyId%3Dtestid&Action%3DDescribeRegions&Format%3DXML&SignatureMethod%3DHMAC-SHA1&SignatureNonce%3D3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&SignatureVersion%3D1.0&TimeStamp%3D2016-02-23T12%253A46%253A24Z&Version%3D2014-05-26 因为 Access Key Secret 为 testsecret,所以用于计算 HMAC 的 Key为 testsecret&,计算得到的签名值为:    CT9X0VtwR86fNWSnsc6v8YGOjuE= 将签名作为 Signature 参数加入到 URL 请求中,最后得到的 URL 为:    http://ecs.aliyuncs.com/?SignatureVersion=1.0&Action=DescribeRegions&Format=XML&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&AccessKeyId=testid&Signature=CT9X0VtwR86fNWSnsc6v8YGOjuE%3D&SignatureMethod=HMAC-SHA1&TimeStamp=2016-02-23T12%3A46%3A24Z [font='iconfont'] Java 示例代码 本示例不需要依赖第三方的库包,可以直接使用。签名步骤如下所示。 构造规范化的请求字符串(排序及 URL 编码)。 public static Map<String, String> splitQueryString(String url)         throws URISyntaxException, UnsupportedEncodingException {     URI uri = new URI(url);     String query = uri.getQuery();     final String[] pairs = query.split("&");     TreeMap<String, String> queryMap = new TreeMap<String, String>();     for (String pair : pairs) {         final int idx = pair.indexOf("=");         final String key = idx > 0 ? pair.substring(0, idx) : pair;         if (!queryMap.containsKey(key)) {             queryMap.put(key, URLDecoder.decode(pair.substring(idx + 1),                     CHARSET_UTF8));         }     }     return queryMap; }/** 对参数名称和参数值进行URL编码**/ public static String generate(String method, Map<String, String> parameter,                               String accessKeySecret) throws Exception {     String signString = generateSignString(method, parameter);     System.out.println("signString---" + signString);     byte[] signBytes = hmacSHA1Signature(accessKeySecret + "&", signString);     String signature = newStringByBase64(signBytes);     System.out.println("signature---" + signature);     if ("POST".equals(method))         return signature;     return URLEncoder.encode(signature, "UTF-8"); } 构造成待签名的字符串。 public static String generateSignString(String httpMethod,                                         Map<String, String> parameter) throws IOException {     TreeMap<String, String> sortParameter = new TreeMap<String, String>();     sortParameter.putAll(parameter);     String canonicalizedQueryString = UrlUtil.generateQueryString(             sortParameter, true);     if (null == httpMethod) {         throw new RuntimeException("httpMethod can not be empty");     }     /** 构造待签名的字符串* */     StringBuilder stringToSign = new StringBuilder();     stringToSign.append(httpMethod).append(SEPARATOR);     stringToSign.append(percentEncode("/")).append(SEPARATOR);     stringToSign.append(percentEncode(canonicalizedQueryString));     return stringToSign.toString(); } 计算待签名字符串的 HMAC 值。 public static byte[] hmacSHA1Signature(String secret, String baseString)         throws Exception {     if (isEmpty(secret)) {         throw new IOException("secret can not be empty");     }     if (isEmpty(baseString)) {         return null;     }     Mac mac = Mac.getInstance("HmacSHA1");     SecretKeySpec keySpec = new SecretKeySpec(             secret.getBytes(CHARSET_UTF8), ALGORITHM);     mac.init(keySpec);     return mac.doFinal(baseString.getBytes(CHARSET_UTF8)); } private static boolean isEmpty(String str) {    return (str == null || str.length() == 0); } 按照 Base64 编码规则编码成字符串,获取签名值。 public static String newStringByBase64(byte[] bytes)         throws UnsupportedEncodingException {     if (bytes == null || bytes.length == 0) {         return null;     }     return new String(new BASE64Encoder().encode(bytes)); } public static String composeStringToSign(Map<String, String> queries) {     String[] sortedKeys = (String[]) queries.keySet()             .toArray(new String[0]);     Arrays.sort(sortedKeys);     StringBuilder canonicalizedQueryString = new StringBuilder();     for (String key : sortedKeys) {            canonicalizedQueryString.append("&").append(percentEncode(key))                 .append("=")                 .append(percentEncode((String) queries.get(key)));     }     StringBuilder stringToSign = new StringBuilder();     stringToSign.append("GET");     stringToSign.append("&");     stringToSign.append(percentEncode("/"));     stringToSign.append("&");        stringToSign.append(percentEncode(canonicalizedQueryString.toString()             .substring(1)));     return stringToSign.toString(); } public static String percentEncode(String value) {     try {         return value == null ? null : URLEncoder                 .encode(value, CHARSET_UTF8).replace("+", "%20")                 .replace("*", "%2A").replace("%7E", "~");     } catch (Exception e) {     }     return ""; } /**  * get SignatureNonce  ** */ public static String getUniqueNonce() {     UUID uuid = UUID.randomUUID();     return uuid.toString(); } /**  * get timestamp  **/ public static String getISO8601Time() {     Date nowDate = new Date();     SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");     df.setTimeZone(new SimpleTimeZone(0, "GMT"));     return df.format(nowDate); } 添加签名。 public static String composeUrl(String endpoint, Map<String, String> queries)         throws UnsupportedEncodingException {     Map<String, String> mapQueries = queries;     StringBuilder urlBuilder = new StringBuilder("");     urlBuilder.append("http");     urlBuilder.append("://").append(endpoint);     if (-1 == urlBuilder.indexOf("?")) {         urlBuilder.append("/?");     }     urlBuilder.append(concatQueryString(mapQueries));     return urlBuilder.toString(); } public static String concatQueryString(Map<String, String> parameters)         throws UnsupportedEncodingException {     if (null == parameters) {         return null;     }     StringBuilder urlBuilder = new StringBuilder("");     for (Map.Entry<String, String> entry : parameters.entrySet()) {         String key = (String) entry.getKey();         String val = (String) entry.getValue();         urlBuilder.append(encode(key));         if (val != null) {             urlBuilder.append("=").append(encode(val));         }         urlBuilder.append("&");     }     int strIndex = urlBuilder.length();     if (parameters.size() > 0) {         urlBuilder.deleteCharAt(strIndex - 1);     }     return urlBuilder.toString(); } public static String encode(String value)         throws UnsupportedEncodingException {     return URLEncoder.encode(value, "UTF-8"); }} [font='iconfont'] API 调用示例 [font='iconfont'] 示例 1 /* * Demo_01: Build a immutable signature instance and print out; * The Signature's toString() function will invoke signature's get() function. */out("output: " +        Signature.newBuilder()            .method(The.HTTP.GET.method())            .url(URL)            .secret(The.API.secret())            .build()); [font='iconfont'] 示例 2 /* * Demo_02: Build a real signature and compose a request url to invoke DescribeRegions api call; */对一个真实的 API URL 进行签名final String ACTION = "DescribeRegions";final String API_URL = The.API.build(ACTION);out(httpGet(Signature.newBuilder()                .method(The.HTTP.GET.method())                .url(API_URL)                .secret(The.API.secret())                .build()                .compose())); 为了方便您快速使用签名机制,您可以在 这里下载完整的示例代码。 注意:您需要将 ACCESS 和 SECRET 替换为您的 Access Key ID 和 Access KeySecret。
问答
算法 · Java · API · PHP · 开发工具 · C# · 数据安全/隐私保护 · Python
2017-10-30
phpMyAdmin连接RDS实例出现的问题,求助
我在一台ECS上,搭了一个phpMyAdmin,配置了新RDS的连接,登陆以后所有操作页面都会出现如下错误警告,但不影响数据库操作: 这个phpMyAdmin下,我还配置了另外一个ECS自建mysql,和一个试用版的RDS实例,却都是正常的,请大神们指教,谢谢~ 警告信息: Notice in ./libraries/DatabaseInterface.class.php#2299 Undefined offset: 1 Backtrace ./libraries/server_common.inc.php#36: PMA_DatabaseInterface->isUserType(string 'grant') ./index.php#110: include(./libraries/server_common.inc.php) Notice in ./libraries/DatabaseInterface.class.php#2294 Undefined offset: 1 Backtrace ./libraries/server_common.inc.php#37: PMA_DatabaseInterface->isUserType(string 'create') ./index.php#110: include(./libraries/server_common.inc.php)
问答
弹性计算 · 关系型数据库 · 数据库 · RDS
2015-05-08
【入门教程系列】Linux系统apache环境设置伪静态(适用于新手初级站长)
很多新手站长不会设置伪静态,这里教一下,按照流程做,100%不会出错。首先,请确认你是官方帮你安装的Linux系统,apache环境 步骤: 一、修改httpd.conf文件 登陆服务器:用putty中文版 工具,具体操作请看教程: http://bbs.aliyun.com/read.php?tid=10719 登陆后,输入命令: cd /aliyun/webserver/apache2.2.15/conf vi + httpd.conf 按字母“I”键进入编辑模式 查找“LoadModule rewrite_module modules/mod_rewrite.so” ,把这句前面的“#”号去掉 查找绑定域名的配置语句“AllowOverride None”,改成“AllowOverride all ” 按Esc键,输入“:wq ”,再输入 “cp httpd.conf httpd.conf.bak” 输入"cd",再重启apache,输入“/aliyun/webserver/apache2.2.15/bin/apachectl restart” 二、加入.htaccess文件 以discuz为例,将.htaccess文件以ftp方式上传到论坛根目录里(注意:传输模式用二进制) 附:.htaccess里的内容: # 将 RewriteEngine 模式打开 RewriteEngine On # 修改以下语句中的 /discuz 为你的论坛目录地址,如果程序放在根目录中,请将 /discuz 修改为 / RewriteBase / # Rewrite 系统规则请勿修改 RewriteCond %{QUERY_STRING} ^(.*)$ RewriteRule ^topic-(.+)\.html$ portal.php?mod=topic&topic=$1&%1 RewriteCond %{QUERY_STRING} ^(.*)$ RewriteRule ^article-([0-9]+)-([0-9]+)\.html$ portal.php?mod=view&aid=$1&page=$2&%1 RewriteCond %{QUERY_STRING} ^(.*)$ RewriteRule ^forum-(\w+)-([0-9]+)\.html$ forum.php?mod=forumdisplay&fid=$1&page=$2&%1 RewriteCond %{QUERY_STRING} ^(.*)$ RewriteRule ^thread-([0-9]+)-([0-9]+)-([0-9]+)\.html$ forum.php?mod=viewthread&tid=$1&extra=page\%3D$3&page=$2&%1 RewriteCond %{QUERY_STRING} ^(.*)$ RewriteRule ^group-([0-9]+)-([0-9]+)\.html$ forum.php?mod=group&fid=$1&page=$2&%1 RewriteCond %{QUERY_STRING} ^(.*)$ RewriteRule ^space-(username|uid)-(.+)\.html$ home.php?mod=space&$1=$2&%1 RewriteCond %{QUERY_STRING} ^(.*)$ RewriteRule ^blog-([0-9]+)-([0-9]+)\.html$ home.php?mod=space&uid=$1&do=blog&id=$2&%1 RewriteCond %{QUERY_STRING} ^(.*)$ RewriteRule ^archiver/(fid|tid)-([0-9]+)\.html$ archiver/index.php?action=$1&value=$2&%1               相关教程: 【入门教程系列】Linux系统建站完整教程 【入门教程系列】mysql数据迁移傻瓜版教程 【入门教程系列】Linux系统apache环境设置伪静态
问答
关系型数据库 · MySQL · Linux · Apache
2011-10-29
什么是API 签名机制?
阿里云产品服务会对每个访问请求进行身份验证,所以无论您使用 HTTP 还是 HTTPS 协议提交请求,都需要在请求中包含签名(Signature)信息。 签名需要您在控制台 Access Key 管理 页面获得 Access Key ID 和 Access Key Secret,进行对称加密来验证请求的发送者身份。其中,Access Key ID 用于标识访问者身份;Access Key Secret 是用于加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密。 注意:阿里云提供了 Python、Java、PHP 和 C# 等语言的 SDK 及第三方 SDK,可以免去您对签名算法进行编码的麻烦。您可以从 这里 了解更多阿里云 SDK 的信息。 签名操作 您在访问时,需要按照下面的方法对请求进行签名处理。 构造规范化的请求字符串(Canonicalized Query String)。按参数名进行排序。按照参数名称的字典顺序对请求中所有的请求参数进行排序,包括“公共请求参数”(不包括 Signature 参数)和接口的自定义参数。 注意:当使用 GET 方法提交请求时,这些参数就是请求 URI 中的参数部分(即 URI 中“?”之后由“&”连接的部分)。 对参数名称和参数值进行 URL 编码。名称和值要使用 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 替换回波浪号(~),即可得到上述规则描述的编码字符串。 对编码后的参数名称和值使用英文等号(=)进行连接。 按参数名称的字典顺序,把英文等号连接得到字符串依次使用 & 符号连接,即得到规范化请求字符串。 构造被签名字符串。 基于步骤 1 得到的规范化字符串构造用于计算签名的字符串,可参考如下规则:<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> StringToSign=     HTTPMethod + “&” +     percentEncode(“/”) + ”&” +      percentEncode(CanonicalizedQueryString) 其中: HTTPMethod 是提交请求用的 HTTP 方法,比如 GET。percentEncode(“/”) 是按照步骤 1.i 中描述的 URL 编码规则对字符 “/” 进行编码得到的值,即 %2F。 percentEncode(CanonicalizedQueryString) 是对步骤 1 中构造的规范化请求字符串按步骤 1.ii 中描述的 URL 编码规则编码后得到的字符串。 计算 HMAC 值。 按照 RFC2104 的定义,使用步骤 2 得到的字符串计算签名 HMAC 值。 注意:计算签名时使用的 Key 就是您持有的 Access Key Secret 并加上一个 “&” 字符(ASCII:38),使用的哈希算法是 SHA1。 计算签名值。 按照 Base64 编码规则 把步骤 3 中的 HMAC 值编码成字符串,即得到签名值(Signature)。 添加签名。 将得到的签名值作为 Signature 参数添加到请求参数中,即完成对请求签名的过程。 注意:得到的签名值在作为最后的请求参数值提交给服务器时,要和其它参数一样,按照 RFC3986 的规则进行 URL 编码。 示例 以 DescribeRegions 为例,假设使用的 Access Key Id 为 testid, Access Key Secret 为 testsecret。 那么签名前的请求 URL 为:<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums="">    http://ecs.aliyuncs.com/?TimeStamp=2016-02-23T12:46:24Z&Format=XML&AccessKeyId=testid&Action=DescribeRegions&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&SignatureVersion=1.0 计算得到的待签名字符串 StringToSign 为:<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums="">    GET&%2F&AccessKeyId%3Dtestid&Action%3DDescribeRegions&Format%3DXML&SignatureMethod%3DHMAC-SHA1&SignatureNonce%3D3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&SignatureVersion%3D1.0&TimeStamp%3D2016-02-23T12%253A46%253A24Z&Version%3D2014-05-26 因为 Access Key Secret 为 testsecret,所以用于计算 HMAC 的 Key 为 testsecret&,计算得到的签名值为:<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums="">    CT9X0VtwR86fNWSnsc6v8YGOjuE= 将签名作为 Signature 参数加入到 URL 请求中,最后得到的 URL 为:<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums="">    http://ecs.aliyuncs.com/?SignatureVersion=1.0&Action=DescribeRegions&Format=XML&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&AccessKeyId=testid&Signature=CT9X0VtwR86fNWSnsc6v8YGOjuE%3D&SignatureMethod=HMAC-SHA1&TimeStamp=2016-02-23T12%3A46%3A24Z Java 示例代码 本示例不需要依赖第三方的库包,可以直接使用。签名步骤如下所示。 构造规范化的请求字符串(排序及 URL 编码)。<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> public static Map<String, String> splitQueryString(String url)         throws URISyntaxException, UnsupportedEncodingException {     URI uri = new URI(url);     String query = uri.getQuery();     final String[] pairs = query.split("&");     TreeMap<String, String> queryMap = new TreeMap<String, String>();     for (String pair : pairs) {         final int idx = pair.indexOf("=");         final String key = idx > 0 ? pair.substring(0, idx) : pair;         if (!queryMap.containsKey(key)) {             queryMap.put(key, URLDecoder.decode(pair.substring(idx + 1),                     CHARSET_UTF8));         }     }     return queryMap; }/** 对参数名称和参数值进行URL编码**/ public static String generate(String method, Map<String, String> parameter,                               String accessKeySecret) throws Exception {     String signString = generateSignString(method, parameter);     System.out.println("signString---" + signString);     byte[] signBytes = hmacSHA1Signature(accessKeySecret + "&", signString);     String signature = newStringByBase64(signBytes);     System.out.println("signature---" + signature);     if ("POST".equals(method))         return signature;     return URLEncoder.encode(signature, "UTF-8"); } 构造成待签名的字符串。<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> public static String generateSignString(String httpMethod,                                         Map<String, String> parameter) throws IOException {     TreeMap<String, String> sortParameter = new TreeMap<String, String>();     sortParameter.putAll(parameter);     String canonicalizedQueryString = UrlUtil.generateQueryString(             sortParameter, true);     if (null == httpMethod) {         throw new RuntimeException("httpMethod can not be empty");     }     /** 构造待签名的字符串* */     StringBuilder stringToSign = new StringBuilder();     stringToSign.append(httpMethod).append(SEPARATOR);     stringToSign.append(percentEncode("/")).append(SEPARATOR);     stringToSign.append(percentEncode(canonicalizedQueryString));     return stringToSign.toString(); } 计算待签名字符串的 HMAC 值。<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> public static byte[] hmacSHA1Signature(String secret, String baseString)         throws Exception {     if (isEmpty(secret)) {         throw new IOException("secret can not be empty");     }     if (isEmpty(baseString)) {         return null;     }     Mac mac = Mac.getInstance("HmacSHA1");     SecretKeySpec keySpec = new SecretKeySpec(             secret.getBytes(CHARSET_UTF8), ALGORITHM);     mac.init(keySpec);     return mac.doFinal(baseString.getBytes(CHARSET_UTF8)); } private static boolean isEmpty(String str) {    return (str == null || str.length() == 0); } 按照 Base64 编码规则编码成字符串,获取签名值。<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> public static String newStringByBase64(byte[] bytes)         throws UnsupportedEncodingException {     if (bytes == null || bytes.length == 0) {         return null;     }     return new String(new BASE64Encoder().encode(bytes)); } public static String composeStringToSign(Map<String, String> queries) {     String[] sortedKeys = (String[]) queries.keySet()             .toArray(new String[0]);     Arrays.sort(sortedKeys);     StringBuilder canonicalizedQueryString = new StringBuilder();     for (String key : sortedKeys) {            canonicalizedQueryString.append("&").append(percentEncode(key))                 .append("=")                 .append(percentEncode((String) queries.get(key)));     }     StringBuilder stringToSign = new StringBuilder();     stringToSign.append("GET");     stringToSign.append("&");     stringToSign.append(percentEncode("/"));     stringToSign.append("&");        stringToSign.append(percentEncode(canonicalizedQueryString.toString()             .substring(1)));     return stringToSign.toString(); } public static String percentEncode(String value) {     try {         return value == null ? null : URLEncoder                 .encode(value, CHARSET_UTF8).replace("+", "%20")                 .replace("*", "%2A").replace("%7E", "~");     } catch (Exception e) {     }     return ""; } /**  * get SignatureNonce  ** */ public static String getUniqueNonce() {     UUID uuid = UUID.randomUUID();     return uuid.toString(); } /**  * get timestamp  **/ public static String getISO8601Time() {     Date nowDate = new Date();     SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");     df.setTimeZone(new SimpleTimeZone(0, "GMT"));     return df.format(nowDate); } 添加签名。<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> public static String composeUrl(String endpoint, Map<String, String> queries)         throws UnsupportedEncodingException {     Map<String, String> mapQueries = queries;     StringBuilder urlBuilder = new StringBuilder("");     urlBuilder.append("http");     urlBuilder.append("://").append(endpoint);     if (-1 == urlBuilder.indexOf("?")) {         urlBuilder.append("/?");     }     urlBuilder.append(concatQueryString(mapQueries));     return urlBuilder.toString(); } public static String concatQueryString(Map<String, String> parameters)         throws UnsupportedEncodingException {     if (null == parameters) {         return null;     }     StringBuilder urlBuilder = new StringBuilder("");     for (Map.Entry<String, String> entry : parameters.entrySet()) {         String key = (String) entry.getKey();         String val = (String) entry.getValue();         urlBuilder.append(encode(key));         if (val != null) {             urlBuilder.append("=").append(encode(val));         }         urlBuilder.append("&");     }     int strIndex = urlBuilder.length();     if (parameters.size() > 0) {         urlBuilder.deleteCharAt(strIndex - 1);     }     return urlBuilder.toString(); } public static String encode(String value)         throws UnsupportedEncodingException {     return URLEncoder.encode(value, "UTF-8"); }} API 调用示例 示例 1 <pre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> /* * Demo_01: Build a immutable signature instance and print out; * The Signature's toString() function will invoke signature's get() function. */out("output: " +        Signature.newBuilder()            .method(The.HTTP.GET.method())            .url(URL)            .secret(The.API.secret())            .build()); 示例 2 <pre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> /* * Demo_02: Build a real signature and compose a request url to invoke DescribeRegions api call; */对一个真实的 API URL 进行签名final String ACTION = "DescribeRegions";final String API_URL = The.API.build(ACTION);out(httpGet(Signature.newBuilder()                .method(The.HTTP.GET.method())                .url(API_URL)                .secret(The.API.secret())                .build()                .compose())); 为了方便您快速使用签名机制,您可以在 这里 下载完整的示例代码。 注意:您需要将 ACCESS 和 SECRET 替换为您的 Access Key ID 和 Access Key Secret。
问答
算法 · Java · API · PHP · 开发工具 · C# · 数据安全/隐私保护 · Python
2017-10-24
API 签名机制是什么?
阿里云产品服务会对每个访问请求进行身份验证,所以无论您使用 HTTP 还是 HTTPS 协议提交请求,都需要在请求中包含签名(Signature)信息。 签名需要您在控制台 Access Key 管理 页面获得 Access Key ID 和 Access Key Secret,进行对称加密来验证请求的发送者身份。其中,Access Key ID 用于标识访问者身份;Access Key Secret 是用于加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密。 注意:阿里云提供了 Python、Java、PHP 和 C# 等语言的 SDK 及第三方 SDK,可以免去您对签名算法进行编码的麻烦。您可以从 这里 了解更多阿里云 SDK 的信息。 签名操作 您在访问时,需要按照下面的方法对请求进行签名处理。 构造规范化的请求字符串(Canonicalized Query String)。按参数名进行排序。按照参数名称的字典顺序对请求中所有的请求参数进行排序,包括“公共请求参数”(不包括 Signature 参数)和接口的自定义参数。 注意:当使用 GET 方法提交请求时,这些参数就是请求 URI 中的参数部分(即 URI 中“?”之后由“&”连接的部分)。 对参数名称和参数值进行 URL 编码。名称和值要使用 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 替换回波浪号(~),即可得到上述规则描述的编码字符串。 对编码后的参数名称和值使用英文等号(=)进行连接。 按参数名称的字典顺序,把英文等号连接得到字符串依次使用 & 符号连接,即得到规范化请求字符串。 构造被签名字符串。 基于步骤 1 得到的规范化字符串构造用于计算签名的字符串,可参考如下规则:<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> StringToSign=     HTTPMethod + “&” +     percentEncode(“/”) + ”&” +      percentEncode(CanonicalizedQueryString) 其中: HTTPMethod 是提交请求用的 HTTP 方法,比如 GET。percentEncode(“/”) 是按照步骤 1.i 中描述的 URL 编码规则对字符 “/” 进行编码得到的值,即 %2F。 percentEncode(CanonicalizedQueryString) 是对步骤 1 中构造的规范化请求字符串按步骤 1.ii 中描述的 URL 编码规则编码后得到的字符串。 计算 HMAC 值。 按照 RFC2104 的定义,使用步骤 2 得到的字符串计算签名 HMAC 值。 注意:计算签名时使用的 Key 就是您持有的 Access Key Secret 并加上一个 “&” 字符(ASCII:38),使用的哈希算法是 SHA1。 计算签名值。 按照 Base64 编码规则 把步骤 3 中的 HMAC 值编码成字符串,即得到签名值(Signature)。 添加签名。 将得到的签名值作为 Signature 参数添加到请求参数中,即完成对请求签名的过程。 注意:得到的签名值在作为最后的请求参数值提交给服务器时,要和其它参数一样,按照 RFC3986 的规则进行 URL 编码。 示例 以 DescribeRegions 为例,假设使用的 Access Key Id 为 testid, Access Key Secret 为 testsecret。 那么签名前的请求 URL 为:<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); color: rgb(51, 51, 51); text-transform: none; text-indent: 0px; letter-spacing: normal; overflow: auto; word-spacing: 0px; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; orphans: 2; widows: 2; font-size-adjust: none; font-stretch: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;' prettyprinted?="" linenums="">    http://ecs.aliyuncs.com/?TimeStamp=2016-02-23T12:46:24Z&Format=XML&AccessKeyId=testid&Action=DescribeRegions&SignatureMethod=HMAC-SHA1&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&SignatureVersion=1.0 计算得到的待签名字符串 StringToSign 为:<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); color: rgb(51, 51, 51); text-transform: none; text-indent: 0px; letter-spacing: normal; overflow: auto; word-spacing: 0px; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; orphans: 2; widows: 2; font-size-adjust: none; font-stretch: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;' prettyprinted?="" linenums="">    GET&%2F&AccessKeyId%3Dtestid&Action%3DDescribeRegions&Format%3DXML&SignatureMethod%3DHMAC-SHA1&SignatureNonce%3D3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&SignatureVersion%3D1.0&TimeStamp%3D2016-02-23T12%253A46%253A24Z&Version%3D2014-05-26 因为 Access Key Secret 为 testsecret,所以用于计算 HMAC 的 Key 为 testsecret&,计算得到的签名值为:<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); color: rgb(51, 51, 51); text-transform: none; text-indent: 0px; letter-spacing: normal; overflow: auto; word-spacing: 0px; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; orphans: 2; widows: 2; font-size-adjust: none; font-stretch: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;' prettyprinted?="" linenums="">    CT9X0VtwR86fNWSnsc6v8YGOjuE= 将签名作为 Signature 参数加入到 URL 请求中,最后得到的 URL 为:<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); color: rgb(51, 51, 51); text-transform: none; text-indent: 0px; letter-spacing: normal; overflow: auto; word-spacing: 0px; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; orphans: 2; widows: 2; font-size-adjust: none; font-stretch: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;' prettyprinted?="" linenums="">    http://ecs.aliyuncs.com/?SignatureVersion=1.0&Action=DescribeRegions&Format=XML&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2014-05-26&AccessKeyId=testid&Signature=CT9X0VtwR86fNWSnsc6v8YGOjuE%3D&SignatureMethod=HMAC-SHA1&TimeStamp=2016-02-23T12%3A46%3A24Z Java 示例代码 本示例不需要依赖第三方的库包,可以直接使用。签名步骤如下所示。 构造规范化的请求字符串(排序及 URL 编码)。<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> public static Map<String, String> splitQueryString(String url)         throws URISyntaxException, UnsupportedEncodingException {     URI uri = new URI(url);     String query = uri.getQuery();     final String[] pairs = query.split("&");     TreeMap<String, String> queryMap = new TreeMap<String, String>();     for (String pair : pairs) {         final int idx = pair.indexOf("=");         final String key = idx > 0 ? pair.substring(0, idx) : pair;         if (!queryMap.containsKey(key)) {             queryMap.put(key, URLDecoder.decode(pair.substring(idx + 1),                     CHARSET_UTF8));         }     }     return queryMap; }/** 对参数名称和参数值进行URL编码**/ public static String generate(String method, Map<String, String> parameter,                               String accessKeySecret) throws Exception {     String signString = generateSignString(method, parameter);     System.out.println("signString---" + signString);     byte[] signBytes = hmacSHA1Signature(accessKeySecret + "&", signString);     String signature = newStringByBase64(signBytes);     System.out.println("signature---" + signature);     if ("POST".equals(method))         return signature;     return URLEncoder.encode(signature, "UTF-8"); } 构造成待签名的字符串。<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> public static String generateSignString(String httpMethod,                                         Map<String, String> parameter) throws IOException {     TreeMap<String, String> sortParameter = new TreeMap<String, String>();     sortParameter.putAll(parameter);     String canonicalizedQueryString = UrlUtil.generateQueryString(             sortParameter, true);     if (null == httpMethod) {         throw new RuntimeException("httpMethod can not be empty");     }     /** 构造待签名的字符串* */     StringBuilder stringToSign = new StringBuilder();     stringToSign.append(httpMethod).append(SEPARATOR);     stringToSign.append(percentEncode("/")).append(SEPARATOR);     stringToSign.append(percentEncode(canonicalizedQueryString));     return stringToSign.toString(); } 计算待签名字符串的 HMAC 值。<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> public static byte[] hmacSHA1Signature(String secret, String baseString)         throws Exception {     if (isEmpty(secret)) {         throw new IOException("secret can not be empty");     }     if (isEmpty(baseString)) {         return null;     }     Mac mac = Mac.getInstance("HmacSHA1");     SecretKeySpec keySpec = new SecretKeySpec(             secret.getBytes(CHARSET_UTF8), ALGORITHM);     mac.init(keySpec);     return mac.doFinal(baseString.getBytes(CHARSET_UTF8)); } private static boolean isEmpty(String str) {    return (str == null || str.length() == 0); } 按照 Base64 编码规则编码成字符串,获取签名值。<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> public static String newStringByBase64(byte[] bytes)         throws UnsupportedEncodingException {     if (bytes == null || bytes.length == 0) {         return null;     }     return new String(new BASE64Encoder().encode(bytes)); } public static String composeStringToSign(Map<String, String> queries) {     String[] sortedKeys = (String[]) queries.keySet()             .toArray(new String[0]);     Arrays.sort(sortedKeys);     StringBuilder canonicalizedQueryString = new StringBuilder();     for (String key : sortedKeys) {            canonicalizedQueryString.append("&").append(percentEncode(key))                 .append("=")                 .append(percentEncode((String) queries.get(key)));     }     StringBuilder stringToSign = new StringBuilder();     stringToSign.append("GET");     stringToSign.append("&");     stringToSign.append(percentEncode("/"));     stringToSign.append("&");        stringToSign.append(percentEncode(canonicalizedQueryString.toString()             .substring(1)));     return stringToSign.toString(); } public static String percentEncode(String value) {     try {         return value == null ? null : URLEncoder                 .encode(value, CHARSET_UTF8).replace("+", "%20")                 .replace("*", "%2A").replace("%7E", "~");     } catch (Exception e) {     }     return ""; } /**  * get SignatureNonce  ** */ public static String getUniqueNonce() {     UUID uuid = UUID.randomUUID();     return uuid.toString(); } /**  * get timestamp  **/ public static String getISO8601Time() {     Date nowDate = new Date();     SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");     df.setTimeZone(new SimpleTimeZone(0, "GMT"));     return df.format(nowDate); } 添加签名。<divre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); overflow: auto; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; font-size-adjust: none; font-stretch: normal;' prettyprinted?="" linenums=""> public static String composeUrl(String endpoint, Map<String, String> queries)         throws UnsupportedEncodingException {     Map<String, String> mapQueries = queries;     StringBuilder urlBuilder = new StringBuilder("");     urlBuilder.append("http");     urlBuilder.append("://").append(endpoint);     if (-1 == urlBuilder.indexOf("?")) {         urlBuilder.append("/?");     }     urlBuilder.append(concatQueryString(mapQueries));     return urlBuilder.toString(); } public static String concatQueryString(Map<String, String> parameters)         throws UnsupportedEncodingException {     if (null == parameters) {         return null;     }     StringBuilder urlBuilder = new StringBuilder("");     for (Map.Entry<String, String> entry : parameters.entrySet()) {         String key = (String) entry.getKey();         String val = (String) entry.getValue();         urlBuilder.append(encode(key));         if (val != null) {             urlBuilder.append("=").append(encode(val));         }         urlBuilder.append("&");     }     int strIndex = urlBuilder.length();     if (parameters.size() > 0) {         urlBuilder.deleteCharAt(strIndex - 1);     }     return urlBuilder.toString(); } public static String encode(String value)         throws UnsupportedEncodingException {     return URLEncoder.encode(value, "UTF-8"); }} API 调用示例 示例 1 <pre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); color: rgb(51, 51, 51); text-transform: none; text-indent: 0px; letter-spacing: normal; overflow: auto; word-spacing: 0px; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; orphans: 2; widows: 2; font-size-adjust: none; font-stretch: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;' prettyprinted?="" linenums=""> /* * Demo_01: Build a immutable signature instance and print out; * The Signature's toString() function will invoke signature's get() function. */out("output: " +        Signature.newBuilder()            .method(The.HTTP.GET.method())            .url(URL)            .secret(The.API.secret())            .build()); 示例 2 <pre style='background: rgb(246, 246, 246); font: 12px/1.6 "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace; margin: 0px 0px 16px; padding: 10px; outline: 0px; border-radius: 3px; border: 1px solid rgb(221, 221, 221); color: rgb(51, 51, 51); text-transform: none; text-indent: 0px; letter-spacing: normal; overflow: auto; word-spacing: 0px; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; orphans: 2; widows: 2; font-size-adjust: none; font-stretch: normal; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;' prettyprinted?="" linenums=""> /* * Demo_02: Build a real signature and compose a request url to invoke DescribeRegions api call; */对一个真实的 API URL 进行签名final String ACTION = "DescribeRegions";final String API_URL = The.API.build(ACTION);out(httpGet(Signature.newBuilder()                .method(The.HTTP.GET.method())                .url(API_URL)                .secret(The.API.secret())                .build()                .compose())); 为了方便您快速使用签名机制,您可以在 这里 下载完整的示例代码。
问答
算法 · Java · API · PHP · 开发工具 · C# · 数据安全/隐私保护 · Python
2017-10-25
跳转至:
开发与运维
3681 人关注 | 91401 讨论 | 88079 内容
+ 订阅
  • 云效DevOps实践-如何基于云效实现测试自动化集成和分析
  • Java第二期训练营打卡引导
  • Delta Lake在Soul的应用实践
查看更多 >
安全
694 人关注 | 21382 讨论 | 26415 内容
+ 订阅
  • 应云而生,幽灵的威胁 - 云原生应用交付与运维的思考
  • 阿里云新品发布会周刊第90期 丨 云数据库PostgreSQL版重磅升级开年发布会
  • 3月3日 | 云数据库PostgreSQL版重磅升级开年发布会
查看更多 >
人工智能
1962 人关注 | 7205 讨论 | 33364 内容
+ 订阅
  • 人工智能如何改变制造业和工业物联网?
  • 【产品能力深度解读】连续入围Gartner魔力象限的Quick BI有何魔力?
  • 阿里云AIoT承建项目获评水利部优秀示范工程
查看更多 >
数据库
87794 人关注 | 33969 讨论 | 27365 内容
+ 订阅
  • Delta Lake在Soul的应用实践
  • 阿里云新品发布会周刊第90期 丨 云数据库PostgreSQL版重磅升级开年发布会
  • 3月3日 | 云数据库PostgreSQL版重磅升级开年发布会
查看更多 >
大数据
2091 人关注 | 13731 讨论 | 28563 内容
+ 订阅
  • 【产品能力深度解读】连续入围Gartner魔力象限的Quick BI有何魔力?
  • Delta Lake在Soul的应用实践
  • 阿里云新品发布会周刊第90期 丨 云数据库PostgreSQL版重磅升级开年发布会
查看更多 >