使用依赖
<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 serverprivate 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);//生成keylistString 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与secretKeyCOSCredentials cred = new BasicSessionCredentials(secretId, secretKey, sessionToken);//若key不是以“/”开头,则需要在 key 的开头加上“/”,否则直接 resource_path=keyString 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任务*/@Testpublic void commitVideoDNA() {//存储在cos中的视频keyString 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转化为JSONJSONObject body = XML.toJSONObject(xmlBody);System.out.println("body = " + body);}/*** 获取视频DNA提交任务后的信息,如任务处理状态*/@Testpublic 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库*/@Testpublic 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);}
}