此版本签名方法功能和安全性不如签名鉴权2.0,推荐使用签名鉴权2.0
小鱼服务会对每个API访问请求进行企业身份、签名验证,即每个请求都需要包括企业身份(enterpriseId)和签名信息(signatrue),签名的生成需要enterpriseId和token,所以在使用API之前,您需要从云视讯管理平台获得enterpriseId和token。
待签名的字符串格式如下:
待签名的字符串 =
请求方法 + '\n' +
请求URI + '\n' +
格式化后的请求参数 + '\n' +
Base64(Sha256Hash(请求实体)
假设您要调用的REST API是按云会议室类型查询企业下云会议室列表: Query参数为:
?enterpriseId=****
&type=SDK
&pageIndex=0
&pageSize=1
则需要按如下步骤创建待签名的字符串:
1.1 首先是HTTP请求方法(GET、PUT、POST、DELETE等),后跟换行符。
GET
1.2 添加REST URI,后跟换行符
云服务API的url上基本都有版本信息,这里计算签名的uri从版本信息后面开始,比如说一个API URL为:
https://sdk.xylink.com/api/rest/external/v1/conference/cloudConferenc
那么计算签名用的uri为:
conference/cloudConferenc
1.3 添加格式化后的参数列表,后跟换行符
处理后的参数列表如下:
enterpriseId=40260e9046bae2da238ac0b0c572326b91726a83&
pageIndex=0&
pageSize=10&
type=SD
注意: 为了便于阅读,我们在每个参数对后加了换行,在正式签名时,您的参数列表必须是一行!对于可选参数,如果您在这里计算待签名的字符串时包含了这些参数,那么在请求url里也要包含这些参数,值为空。
1.4 使用 SHA256 哈希函数以基于 Http 或 Https 请求正文中的负载(请求体)创建哈希值,并对哈希做Base64编码 如果负载为空,则用空字符串作为哈希函数的输入,在此例中,负载为空。如果负载的字节数超过100,则只取前100个字节计算。
47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU
java代码生成hash的例子如下:
import org.apache.commons.codec.digest.DigestUtils;
import sun.misc.BASE64Encoder;
public static void main(String[] args) {
BASE64Encoder encoder = new BASE64Encoder();
byte[] data = DigestUtils.sha256("");
System.out.println(encoder.encode(data));
}
对于有负载的PUT和POST,请务必把要传入的Json或者用Java对象序列化后的Json生成Hash,如下例(要传入一个用户数组):
public class Test {
public static void main(String[] args) {
List<UserDto> userDtoList = new ArrayList<> ();
UserDto user = new UserDto();
user.setName("小张");
user.setPhone("13811111111");
userDtoList.add(user);
try {
String str = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(userDtoList);
BASE64Encoder encoder = new BASE64Encoder();
byte[] data = DigestUtils.sha256(str);
System.out.println(encoder.encode(data));
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
1.5 生成的待签名字符串
GET\n
conference/cloudConference\n
enterpriseId=40260e9046bae2da238ac0b0c572326b91726a83&pageIndex=0&pageSize=10&type=SD
java 代码计算签名的方法如下:
import java.security.SignatureException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.axis.encoding.Base64;
public class Signature {
private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
public static String calculateHMAC(String data, String key)
throws java.security.SignatureException
{
String result;
try {
// Get an hmac_sha256 key from the raw key bytes.
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes("UTF8"), HMAC_SHA256_ALGORITHM);
// Get an hmac_sha256 Mac instance and initialize with the signing key.
Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
mac.init(signingKey);
// Compute the hmac on input data bytes.
byte[] rawHmac = mac.doFinal(data.getBytes("UTF8"));
// Base64-encode the hmac by using the utility in the SDK
result = Base64.encode(rawHmac);
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
}
最终调用的create_meeting的URL如下:
https://sdk.xylink.com/api/rest/external/v1/conference/cloudConference?enterpriseId=40260e9046bae2da238ac0b0c572326b91726a83&type=SDK&pageIndex=0&pageSize=10&signature=ytgoQGLkzB04XIjBqpaVEzb%2FtDEC%2Bbe3yym8tc864%2Fc%3
下面是一个token为:GET conference/cloudConference enterpriseId=40260e9046bae2da238ac0b0c572326b91726a83&pageIndex=0&pageSize=10&type=SDK,可以用作验证签名算法的URL:
GET https://sdk.xylink.com/api/rest/external/v1/conference/cloudConference?enterpriseId=40260e9046bae2da238ac0b0c572326b91726a83&type=SDK&pageIndex=0&pageSize=10&signature=ytgoQGLkzB04XIjBqpaVEzb%2FtDEC%2Bbe3yym8tc864%2Fc%3
这个例子中,待签名的字符串是:
String strToSign = "GET\n" +
"conference/cloudConference\n" +
"enterpriseId=40260e9046bae2da238ac0b0c572326b91726a83&pageIndex=0&pageSize=10&type=SDK\n" +
"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
计算出来的签名是:
ytgoQGLkzB04XIjBqpaVEzb%2FtDEC%2Bbe3yym8tc864%2Fc%3
package com.ainemo.libra.web.util;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.SignatureException;
import java.util.<em>;
public class SignatureSample {
private String requestUriPrefix="https://sdk.xylink.com/api/rest/external/v1/";
private String wssPrefix="wss://sdk.xylink.com/external/";
protected String computeStringToSign(String requestPath, Map<String, String> reqParams, String reqJsonEntity, String reqMethod) throws Exception{
String prefix = getPrefix(requestPath);
//1. request method
StringBuffer strToSign = new StringBuffer(reqMethod);
strToSign.append("\n");
//2. request path
strToSign.append(requestPath.substring(prefix.length()));
strToSign.append("\n");
//3. sorted request param and value
List<String> params = new ArrayList<String>(reqParams.keySet());
Collections.sort(params);
for(String param : params) {
strToSign.append(param);
strToSign.append("=");
strToSign.append(reqParams.get(param));
strToSign.append("&");
}
strToSign.deleteCharAt(strToSign.length()-1);
strToSign.append("\n");
byte[] reqEntity = new byte[0];
if (StringUtils.isNotBlank(reqJsonEntity)){
reqEntity = reqJsonEntity.getBytes("utf-8");
}
if(reqEntity.length == 0) {
byte[] entity = DigestUtils.sha256("");
strToSign.append(Base64.encodeBase64String(entity));
} else {
byte[] data = null;
if(reqEntity.length <= 100) {
data = reqEntity;
} else {
data = Arrays.copyOf(reqEntity, 100);
}
byte[] entity = DigestUtils.sha256(data);
strToSign.append(Base64.encodeBase64String(entity));
}
String ret = strToSign.toString();
System.out.println(ret);
System.out.println("------------------");
return ret;
}
private String getPrefix(String reqPath){
String prefix = requestUriPrefix;
if (reqPath.startsWith("wss://")){
prefix = wssPrefix;
}
return prefix;
}
private String calculateHMAC(String data, String key) throws SignatureException {
try {
SecretKeySpec e = new SecretKeySpec(key.getBytes("UTF8"), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(e);
byte[] rawHmac = mac.doFinal(data.getBytes("UTF8"));
String result = Base64.encodeBase64String(rawHmac);
return result;
} catch (Exception var6) {
throw new SignatureException("Failed to generate HMAC : " + var6.getMessage());
}
}
public String computeSignature(String jsonEntity, String method, String token, String reqPath) {
try {
Map<String, String> reqParams = new HashMap<String, String>();
int idx = reqPath.indexOf("?");
String[] params = reqPath.substring(idx + 1).split("&");
for(String param : params) {
String[] pair = param.split("=");
if (pair.length == 1){
reqParams.put(pair[0], "");
}else {
reqParams.put(pair[0], pair[1]);
}
}
reqPath = reqPath.substring(0, idx);
String strToSign = computeStringToSign(reqPath, reqParams, jsonEntity, method);
String mySignature = calculateHMAC(strToSign, token);
mySignature = mySignature.replace(" ", "+");
return URLEncoder.encode(mySignature, "utf-8");
} catch (Exception e) {
return null;
}
}
public static void main(String[] args) throws Exception {
String token = "</em><strong>";
String jsonEntity = "";
//GET 方法签名计算
String urlGET = "https://sdk.xylink.com/api/rest/external/v1/meetingInfo/910077762222?enterpriseId=</strong><em>";
jsonEntity = "";//如有请求体,请赋值
System.out.println(new SignatureSample().computeSignature(jsonEntity, "GET", token, url));
//POST 方法签名计算
String urlPOST = "https://sdk.xylink.com/api/rest/external/v2/create_meeting?enterpriseId=</em><strong>";
jsonEntity = "{
"meetingName": "我要创建云会议室",
"startTime": 1537874159062,
"endTime": 1537881359062,
"requirePassword": true,
"password": "123456",
"controlPassword": "123456",
"configs": {
"autoRecord": false
}
}";
System.out.println(new SignatureSample().computeSignature(jsonEntity, "POST", token, url));
//PUT 方法签名计算
String urlPUT = "https://sdk.xylink.com/api/rest/external/v1/meetingInfo/910077762222?enterpriseId=</strong><em>";
jsonEntity = "{
"meetingName": "我要修改云会议室信息",
"startTime": 1537874159062,
"endTime": 1537881359062,
"requirePassword": false
"controlPassword": "222222"
}";
System.out.println(new SignatureSample().computeSignature(jsonEntity, "PUT", token, url));
//DELETE 方法签名计算
String urlPUT = "https://sdk.xylink.com/api/rest/external/v1/meetingInfo/910077762222?enterpriseId=</em>**";
jsonEntity = "";//如有请求体,请赋值
System.out.println(new SignatureSample().computeSignature(jsonEntity, "DELETE", token, url));
}