使用依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.1</version>
</dependency>
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.6.36</version>
</dependency>
视频DNA校验签名
1、腾讯官方提供的签名工具类
package com.hongmeng.util.tencent;
import static com.qcloud.cos.auth.COSSignerConstants.LINE_SEPARATOR;
import static com.qcloud.cos.auth.COSSignerConstants.Q_AK;
import static com.qcloud.cos.auth.COSSignerConstants.Q_HEADER_LIST;
import static com.qcloud.cos.auth.COSSignerConstants.Q_KEY_TIME;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGNATURE;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_ALGORITHM_KEY;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_ALGORITHM_VALUE;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_TIME;
import static com.qcloud.cos.auth.COSSignerConstants.Q_URL_PARAM_LIST;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import com.qcloud.cos.Headers;
import com.qcloud.cos.auth.AnonymousCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.auth.COSSessionCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.http.CosHttpRequest;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.internal.CosServiceRequest;
import com.qcloud.cos.utils.UrlEncoderUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.HmacUtils;
/**
* @author zym
* date: 2023-10-18 15:44
*/
public class COSSigner {
private static Set<String> needSignedHeaderSet = new HashSet<>();
private Boolean isCIWorkflowRequest = false;
// Time offset between local and server
private int localTimeDelta = 0;
static {
needSignedHeaderSet.add("cache-control");
needSignedHeaderSet.add("content-disposition");
needSignedHeaderSet.add("content-encoding");
needSignedHeaderSet.add("content-length");
needSignedHeaderSet.add("content-md5");
needSignedHeaderSet.add("content-type");
needSignedHeaderSet.add("expect");
needSignedHeaderSet.add("expires");
needSignedHeaderSet.add("host");
needSignedHeaderSet.add("if-match");
needSignedHeaderSet.add("if-modified-since");
needSignedHeaderSet.add("if-none-match");
needSignedHeaderSet.add("if-unmodified-since");
needSignedHeaderSet.add("origin");
needSignedHeaderSet.add("range");
needSignedHeaderSet.add("transfer-encoding");
}
private boolean isAnonymous(COSCredentials cred) {
return cred instanceof AnonymousCOSCredentials;
}
public <X extends CosServiceRequest> void sign(CosHttpRequest<X> request, COSCredentials cred, Date expiredTime) {
if (isAnonymous(cred)) {
return;
}
String authoriationStr =
buildAuthorizationStr(request.getHttpMethod(), request.getResourcePath(),
request.getHeaders(), request.getParameters(), cred, expiredTime, true);
request.addHeader(Headers.COS_AUTHORIZATION, authoriationStr);
if (cred instanceof COSSessionCredentials) {
request.addHeader(Headers.SECURITY_TOKEN,
((COSSessionCredentials) cred).getSessionToken());
}
}
public String buildPostObjectSignature(String secretKey, String keyTime, String policy) {
String signKey = HmacUtils.hmacSha1Hex(secretKey, keyTime);
String stringToSign = DigestUtils.sha1Hex(policy);
return HmacUtils.hmacSha1Hex(signKey, stringToSign);
}
public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path,
COSCredentials cred,
Date expiredTime) {
Date startTime = new Date();
return buildAuthorizationStr(methodName, resouce_path, new HashMap<>(), new HashMap<>(),
cred, startTime, expiredTime, true);
}
public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path,
Map<String, String> headerMap, Map<String, String> paramMap, COSCredentials cred,
Date expiredTime) {
Date startTime = new Date();
return buildAuthorizationStr(methodName, resouce_path, headerMap, paramMap,
cred, startTime, expiredTime,true);
}
public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path,
Map<String, String> headerMap, Map<String, String> paramMap, COSCredentials cred,
Date expiredTime, Boolean signHost) {
Date startTime = new Date();
return buildAuthorizationStr(methodName, resouce_path, headerMap, paramMap,
cred, startTime, expiredTime, signHost);
}
public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path,
Map<String, String> headerMap, Map<String, String> paramMap, COSCredentials cred,
Date startTime, Date expiredTime, Boolean signHost) {
if (isAnonymous(cred)) {
return null;
}
//万象工作流接口会出现uri带问号的情况 例如 /workflow/xxxxxx?active 这种情况?后面的参数不参与鉴权
if (isCIWorkflowRequest){
resouce_path = resouce_path.split("\\?")[0];
}
Map<String, String> signHeaders = buildSignHeaders(headerMap, signHost);
// 签名中的参数和http 头部 都要进行字符串排序
//对请求中的参数和http头部进行处理:对key先urlencode再小写处理,对value进行urlencode处理;
//生成 key 到 value 的映射 Map,根据key按照字典序排序
TreeMap<String, String> encodedSortedSignHeaders = buildEncodeSortedMemberMap(signHeaders);
TreeMap<String, String> encodedSortedParams = buildEncodeSortedMemberMap(paramMap);
//生成keylist
String qHeaderListStr = buildSignMemberStr(encodedSortedSignHeaders);
String qUrlParamListStr = buildSignMemberStr(encodedSortedParams);
String qKeyTimeStr, qSignTimeStr;
qKeyTimeStr = qSignTimeStr = buildTimeStr(startTime, expiredTime);
String signKey = HmacUtils.hmacSha1Hex(cred.getCOSSecretKey(), qKeyTimeStr);
String formatMethod = methodName.toString().toLowerCase();
String formatUri = resouce_path;
String formatParameters = formatMapToStr(encodedSortedParams);
String formatHeaders = formatMapToStr(encodedSortedSignHeaders);
String formatStr = new StringBuilder().append(formatMethod).append(LINE_SEPARATOR)
.append(formatUri).append(LINE_SEPARATOR).append(formatParameters)
.append(LINE_SEPARATOR).append(formatHeaders).append(LINE_SEPARATOR).toString();
String hashFormatStr = DigestUtils.sha1Hex(formatStr);
String stringToSign = new StringBuilder().append(Q_SIGN_ALGORITHM_VALUE)
.append(LINE_SEPARATOR).append(qSignTimeStr).append(LINE_SEPARATOR)
.append(hashFormatStr).append(LINE_SEPARATOR).toString();
String signature = HmacUtils.hmacSha1Hex(signKey, stringToSign);
String authoriationStr = new StringBuilder().append(Q_SIGN_ALGORITHM_KEY).append("=")
.append(Q_SIGN_ALGORITHM_VALUE).append("&").append(Q_AK).append("=")
.append(cred.getCOSAccessKeyId()).append("&").append(Q_SIGN_TIME).append("=")
.append(qSignTimeStr).append("&").append(Q_KEY_TIME).append("=").append(qKeyTimeStr)
.append("&").append(Q_HEADER_LIST).append("=").append(qHeaderListStr).append("&")
.append(Q_URL_PARAM_LIST).append("=").append(qUrlParamListStr).append("&")
.append(Q_SIGNATURE).append("=").append(signature).toString();
return authoriationStr;
}
public boolean needSignedHeader(String header) {
return needSignedHeaderSet.contains(header) || header.startsWith("x-cos-");
}
private Map<String, String> buildSignHeaders(Map<String, String> originHeaders, Boolean signHost) {
Boolean hasHost = false;
Map<String, String> signHeaders = new HashMap<>();
for (Entry<String, String> headerEntry : originHeaders.entrySet()) {
String key = headerEntry.getKey().toLowerCase();
if (key.equals("host")) {
hasHost = true;
}
if(needSignedHeader(key)) {
String value = headerEntry.getValue();
signHeaders.put(key, value);
}
}
if (!hasHost && signHost) {
String msg = String.format("buildAuthorization missing header: host. %s", originHeaders);
throw new CosClientException(msg);
}
return signHeaders;
}
private TreeMap<String, String> buildEncodeSortedMemberMap(Map<String, String> signElements){
TreeMap<String, String> encodeSortedSignElements = new TreeMap<>();
for (Entry<String, String> header : signElements.entrySet()) {
if (header.getKey() == null) {
continue;
}
String encodeLowerKey = UrlEncoderUtils.encode(header.getKey().trim()).toLowerCase();
String value = "";
if (header.getValue()!=null){
value = header.getValue().trim();
}
String encodeValue = UrlEncoderUtils.encode(value);
encodeSortedSignElements.put(encodeLowerKey, encodeValue);
}
return encodeSortedSignElements;
}
private String buildSignMemberStr(Map<String, String> signHeaders) {
StringBuilder strBuilder = new StringBuilder();
boolean seenOne = false;
for (String key : signHeaders.keySet()) {
if (!seenOne) {
seenOne = true;
} else {
strBuilder.append(";");
}
strBuilder.append(key);
}
return strBuilder.toString();
}
private String formatMapToStr(Map<String, String> kVMap) {
StringBuilder strBuilder = new StringBuilder();
boolean seeOne = false;
for (Entry<String, String> entry : kVMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (!seeOne) {
seeOne = true;
} else {
strBuilder.append("&");
}
strBuilder.append(key).append("=").append(value);
}
return strBuilder.toString();
}
private String buildTimeStr(Date startTime, Date endTime) {
StringBuilder strBuilder = new StringBuilder();
long startTimestamp = startTime.getTime() / 1000 + localTimeDelta;
long endTimestamp = endTime.getTime() / 1000 + localTimeDelta;
strBuilder.append(startTimestamp).append(";").append(endTimestamp);
return strBuilder.toString();
}
public static Set<String> getNeedSignedHeaderSet() {
return needSignedHeaderSet;
}
public static void setNeedSignedHeaderSet(Set<String> needSignedHeaderSet) {
COSSigner.needSignedHeaderSet = needSignedHeaderSet;
}
public void setCIWorkflowRequest(Boolean CIRequest) {
isCIWorkflowRequest = CIRequest;
}
public int getLocalTimeDelta() {
return localTimeDelta;
}
public void setLocalTimeDelta(int localTimeDelta) {
this.localTimeDelta = localTimeDelta;
}
}
2、基于腾讯云提供的官方签名方法,做一个适应于自己业务的方法封装
/**
* 获取一个临时签名
* https://cloud.tencent.com/document/product/436/35217#.E7.94.9F.E6.88.90.E7.AD.BE.E5.90.8D
*
* @param methodName 请求的 HTTP 方法
* @param path 需要访问的路径
* @param params 本次请求参数
* @param headers 填写本次请求的头部
*/
public static String getSigner(HttpMethodName methodName, String path, Map<String, String> params, Map<String, String> headers) {
// 这里需要已经获取到临时密钥的结果。
JSONObject credentials = getSnapToken().getJSONObject("credentials");
String sessionToken = credentials.getString("sessionToken");
//腾讯云cos中bucket对应secretId与secretKey
COSCredentials cred = new BasicSessionCredentials(secretId, secretKey, sessionToken);
//若key不是以“/”开头,则需要在 key 的开头加上“/”,否则直接 resource_path=key
String resourcePath = path.startsWith("/") ? path : "/" + path;
// 用来生成签名
COSSigner signer = new COSSigner();
// 这里设置签名在半个小时后过期
Date expirationDate = new Date(System.currentTimeMillis() + 30L * 60L * 1000L);
//获取签名
return signer.buildAuthorizationStr(methodName, resourcePath, headers, params, cred, expirationDate, true);
}
视频DNA相关API
public class CosDNATest {
private final String host = "https://ad-zym-test.ci.ap-guangzhou.myqcloud.com";
//基于HttpClient依赖进行封装的工具类
private final HttpClientUtil instance = HttpClientUtil.getInstance();
/**
* 提交一个视频DNA任务
*/
@Test
public void commitVideoDNA() {
//存储在cos中的视频key
String key = "2023-10-12/8d00c3344784276dd9b3e19447638c57.mp4";
String reqStr = "<Request>" +
" <Tag>DNA</Tag>" +
" <Input>" +
" <Object>" + key + "</Object>" +
" </Input>" +
" <Operation>" +
" <DnaConfig>" +
" <RuleType>GetFingerPrint</RuleType>" +
" <DnaDbId>dev_238</DnaDbId>" +
" </DnaConfig>" +
" <UserData>zym</UserData>" +
" <JobLevel>0</JobLevel>" +
" </Operation>" +
" <CallBackType>Url</CallBackType>" +
" <CallBack>http://adtech.test.link.hmgreat.com:8089/dnaCallBack</CallBack>" +
" <CallBackFormat>JSON</CallBackFormat>" +
"</Request>";
Map<String, String> headers = new HashMap<>();
headers.put("host", "ad-zym-test.ci.ap-guangzhou.myqcloud.com");
//获取本次任务提交的签名
String signer = TencentCosUtil.getSigner(HttpMethodName.POST, "/jobs", Collections.emptyMap(), headers);
headers.put("Content-Type", "application/xml");
headers.put("Authorization", signer);
String xmlBody = instance.postHttpResponseXmlBody(host + "/jobs", headers, reqStr);
//将XML转化为JSON
JSONObject body = XML.toJSONObject(xmlBody);
System.out.println("body = " + body);
}
/**
* 获取视频DNA提交任务后的信息,如任务处理状态
*/
@Test
public void getVideoDNAJobInfo() {
String tempUrl = host + "/jobs/j5894a76c6e2311eeb97b6d08ebe82b8f";
Map<String, String> headers = new HashMap<>();
headers.put("host", "ad-zym-test.ci.ap-guangzhou.myqcloud.com");
String signer = TencentCosUtil.getSigner(HttpMethodName.GET, "/jobs/j5894a76c6e2311eeb97b6d08ebe82b8f", Collections.emptyMap(), headers);
headers.put("Authorization", signer);
String responseBody = instance.getHttpResponseBody(tempUrl, headers);
System.out.println("responseBody = " + responseBody);
}
/**
* 查询cos中对应bucket所关联的DNA库
*/
@Test
public void getDnaDBList() {
String tempUrl = host + "/dnadb";
Map<String, String> headers = new HashMap<>();
headers.put("host", "ad-zym-test.ci.ap-guangzhou.myqcloud.com");
String signer = TencentCosUtil.getSigner(HttpMethodName.GET, "/dnadb", Collections.emptyMap(), headers);
headers.put("Authorization", signer);
String responseBody = instance.getHttpResponseBody(tempUrl, headers);
System.out.println("responseBody = " + responseBody);
}
}