对于数据安全性要求高的用户,需要对发布的 API 进行更高安全性的鉴权方式设置,需要提供更安全的认证方式,满足更严格的安全要求。
数据发布API支持基于AK/SK认证逻辑的摘要签名认证方式,避免认证信息和请求信息在传输过程中被截获和篡改,提升认证安全性。
FineDataLink 发布的 API 采用 HMAC-SHA256 摘要算法计算签名,验签逻辑为:
请求发起方(计算签名,并在请求中带上签名) ---> 请求接收方(按请求参数计算签名,并校验签名)
用户已经发布API,同时绑定API至应用,设置应用认证方式为摘要认证。
根据下列示例代码,创建JAVA 文件:
package kk;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import java.math.BigInteger;import java.nio.charset.StandardCharsets;import java.security.MessageDigest;import java.util.Base64;import java.util.UUID;public class k { public static void main(String[] args) { //修改为对应的AppSecret String secretKey = "1bbe91b1-a39c-4742-9694-e126bcf9a3bd"; //请求方式,注意大写 String httpMethod = "POST"; //POST请求需要写contentType,GET请求此处写空字符串 String contentType = "application/json"; //API路径。如果是get请求,需要带上参数,例如xxx/xxx?a=1 String pathAndParameters = "a5ce6bb4-467b-46f2-8878-2132635973bb/87"; //body请求体的内容 String data = "{\"paging\":{\"pageSize\":10,\"pageNum\":1},\"params\":[]}"; //Nonce,自动生成 String nonce = String.valueOf(UUID.randomUUID()); //时间戳,自动生成 String timestamp = String.valueOf(System.currentTimeMillis()); //待签名字符串 String stringToSign = httpMethod +"\n"+ nonce +"\n"+ timestamp +"\n"+ pathAndParameters +"\n"+ contentType +"\n"+ md5(data); //签名 String signature = hmacSHA256(secretKey,stringToSign); //拼出完整的Authorization System.out.println("Authorization:\n"+"HMAC-SHA256 Signature="+signature+",Nonce="+nonce+",Timestamp="+timestamp); } /** * 对字符串data进行HmacSHA256签名,以Base64的结果返回 * * @param secretKey 签名密钥 * @param data 待签名字符串 */ public static String hmacSHA256(String secretKey, String data) { try { Mac hmacSha256 = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); hmacSha256.init(secretKeySpec); byte[] hashBytes = hmacSha256.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(hashBytes); } catch (Exception e) { throw new RuntimeException("HmacSha error", e); } } /** * 对字符串data计算md5摘要值,再进行Base64编码,返回编码后的结果 * * @param data 待计算的字符串 */ public static String md5(String data) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.reset(); md.update(data.getBytes(StandardCharsets.UTF_8)); String md5Result = String.format("%032x", new BigInteger(1, md.digest())); return Base64.getEncoder().encodeToString(md5Result.getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { throw new RuntimeException("md5 error", e); } }}
package kk;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import java.math.BigInteger;import java.nio.charset.StandardCharsets;import java.security.MessageDigest;import java.util.Base64;import java.util.UUID;public class k { public static void main(String[] args) { //修改为对应的AppSecret String secretKey = "a07eefc1-4b29-469a-8cb1-f68e3532d3a2"; //请求方式,注意大写 String httpMethod = "GET"; //POST请求需要写contentType,GET请求此处写空字符串 String contentType = ""; //API路径。如果是get请求,需要带上参数,例如xxx/xxx?a=1 String pathAndParameters = "a5ce6bb4-467b-46f2-8878-2132635973bb/dd?pageSize=10&pageNum=1"; //body请求体的内容 String data = ""; //Nonce,自动生成 String nonce = String.valueOf(UUID.randomUUID()); //时间戳,自动生成 String timestamp = String.valueOf(System.currentTimeMillis()); //待签名字符串 String stringToSign = httpMethod +"\n"+ nonce +"\n"+ timestamp +"\n"+ pathAndParameters +"\n"+ contentType +"\n"+ ("".equals(data)?"":md5(data)); //签名 String signature = hmacSHA256(secretKey,stringToSign); //拼出完整的Authorization System.out.println("Authorization:\n"+"HMAC-SHA256 Signature="+signature+",Nonce="+nonce+",Timestamp="+timestamp); } /** * 对字符串data进行HmacSHA256签名,以Base64的结果返回 * * @param secretKey 签名密钥 * @param data 待签名字符串 */ public static String hmacSHA256(String secretKey, String data) { try { Mac hmacSha256 = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); hmacSha256.init(secretKeySpec); byte[] hashBytes = hmacSha256.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(hashBytes); } catch (Exception e) { throw new RuntimeException("HmacSha error", e); } } /** * 对字符串data计算md5摘要值,再进行Base64编码,返回编码后的结果 * * @param data 待计算的字符串 */ public static String md5(String data) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.reset(); md.update(data.getBytes(StandardCharsets.UTF_8)); String md5Result = String.format("%032x", new BigInteger(1, md.digest())); return Base64.getEncoder().encodeToString(md5Result.getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { throw new RuntimeException("md5 error", e); } }}
package kk;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import java.math.BigInteger;import java.nio.charset.StandardCharsets;import java.security.MessageDigest;import java.util.Base64;import java.util.UUID;public class k { public static void main(String[] args) { //修改为对应的AppSecret String secretKey = "1bbe91b1-a39c-4742-9694-e126bcf9a3bd"; //请求方式,注意大写 String httpMethod = "POST"; //POST请求需要写contentType,GET请求此处写空字符串 String contentType = "application/x-www-form-urlencoded"; //API路径。如果是get请求,需要带上参数,例如xxx/xxx?a=1 String pathAndParameters = "a5ce6bb4-467b-46f2-8878-2132635973bb/87"; //body请求体的内容 body里的键值对也要编码 String data = "a=1&b=%E6%8C%AA%E5%A8%81"; //Nonce,自动生成 String nonce = String.valueOf(UUID.randomUUID()); //时间戳,自动生成 String timestamp = String.valueOf(System.currentTimeMillis()); //待签名字符串 String stringToSign = httpMethod +"\n"+ nonce +"\n"+ timestamp +"\n"+ pathAndParameters +"\n"+ contentType +"\n"+ md5(data); //签名 String signature = hmacSHA256(secretKey,stringToSign); //拼出完整的Authorization System.out.println("Authorization:\n"+"HMAC-SHA256 Signature="+signature+",Nonce="+nonce+",Timestamp="+timestamp); } /** * 对字符串data进行HmacSHA256签名,以Base64的结果返回 * * @param secretKey 签名密钥 * @param data 待签名字符串 */ public static String hmacSHA256(String secretKey, String data) { try { Mac hmacSha256 = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); hmacSha256.init(secretKeySpec); byte[] hashBytes = hmacSha256.doFinal(data.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(hashBytes); } catch (Exception e) { throw new RuntimeException("HmacSha error", e); } } /** * 对字符串data计算md5摘要值,再进行Base64编码,返回编码后的结果 * * @param data 待计算的字符串 */ public static String md5(String data) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.reset(); md.update(data.getBytes(StandardCharsets.UTF_8)); String md5Result = String.format("%032x", new BigInteger(1, md.digest())); return Base64.getEncoder().encodeToString(md5Result.getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { throw new RuntimeException("md5 error", e); } }}
客户端需要传入 Authorization 请求头和 Content-Type 头,使用 GET/POST 向客户端发起请求:
算法名称:Signature=Signature值, Nonce=Nonce随机数, Timestamp=Timestamp时间戳
举例:
HMAC-SHA256 Signature=FiXSVh+oBzitw+HDypwlmB0PE+Z67pdXbQM7QyHA7qk=, Nonce=c967a237-cd6c-470e-906f-a8655461897, Timestamp=1686542039670
根据请求的内容类型,填入Content-Type请求头内容。
如果是GET请求头不需要传入 Content-Type。
其中生成 Signature 值作为「待签名字符串」需要的项目如下,其中标注字母的内容需要用户根据自己的实际值进行替换:
应用密钥
在数据服务>应用列表,选择摘要签名,即复制 AppSecret,如下图所示:
请求方法,目前支持传入GET和POST。注:需要大写。
验证时,服务端将会通过此UUID检查近5分钟内是否有重复请求,如果有重复请求,将进行拦截。
13位时间戳(1970-01-01 00:00:00开始到现在的毫秒数),在生成签名的 java 代码中自动生成。
验证时,服务端将会通过此时间戳,检查此请求是否以过期,如果请求已过期,将进行拦截。
API配置页面配置的API路径
如果是 get 请求,需要带上参数,例如xxx/xxx?a=1
示例:http://192.168.5.175:8089/webroot/service/publish/<appid>/api01?a=1&b=2中的加粗部分,不包含首尾的斜杠。
在API列表下的授权应用中复制 API 路径,如下图所示:
BODY的MIME类型。
POST请求需要写 contentType,GET请求此处写空字符串
POST请求时,在BODY中的参数字符串。
对于json:原样所有字符串,包含空格、回车等符号。
对于x-www-form-urlencoded:将键值对分别进行URL转码,然后使用&连接起来;有键无值、有值无键时正常保留等号。
例如 JSON 格式的 Body,示例为:
{"paging":{"pageSize":10,"pageNum":1},"params":[]}
对于以上请求体内容,先做MD5处理(输出32位小写字符串),结果再进行BASE64编码,得到最终的Content-MD5结果。
「待签名字符串」构建方式:
待签名字符串 = 「HTTPMethod」+ "\n"
+「Nonce」+ "\n"
+「Timestamp」+ "\n"
+「PathAndParameters」+ "\n"
+「Content-Type」+ "\n"
+「Content-MD5」
注1:加号代表拼接,实际是每个项目之间通过换行分隔,如果没有对应项目,则对应内容用空字符串代替,但是换行需要保存。
注2:如果没有BODY,那么Content-MD5项目直接为空字符串,不对空BODY做MD5。(也就是说,目前对于 GET 请求,Content-Type和Content-MD5项目都会为空字符串)
待签名字符串生成 Signature 签名,使用 HMAC-SHA256 加密算法。
Mac hmacSha256 = Mac.getInstance("HmacSHA256");byte[] appSecretBytes = appSecret.getBytes(Charset.forName("UTF-8"));hmacSha256.init(new SecretKeySpec(appSecretBytes, 0, appSecretBytes.length, "HmacSHA256"));byte[] md5Result = hmacSha256.doFinal(stringToSign.getBytes(Charset.forName("UTF-8")));String signature = Base64.encodeBase64String(md5Result);
计算签名方式同客户端
校验项目:
参考本文 2.1 节修改代码中的指定内容:
例如用户已经在 FineDataLink 中发布请求为 POST application/json 的 API ,则需要准备以下数据,以备生成待签名字符串:
对于json 格式的 Body,可在API 生成界面复制 Body 值
然后运行 JAVA 文件,即可获得 Authorization ,如下图所示:
此处以 POST JSON 请求为例,输入 Authorization 认证和Body 请求值,即可取出发布的 API 数据,如下图所示:
滑鼠選中內容,快速回饋問題
滑鼠選中存在疑惑的內容,即可快速回饋問題,我們將會跟進處理。
不再提示
10s後關閉
Submitted successfully
Network busy