腾讯云COS储存桶鉴权签名上传下载文件

在业务中需要储存一些文件到储存桶上,在上传下载中存储地址难免暴露在外,在设置储存桶私有访问后需要携带签名访问。签名可分为永久签名-临时签名,更推荐使用临时签名更加安全。

生成临时签名

1.生成临时密钥

  • 使用临时秘钥生成预签名,通过临时授权的方式进一步提高预签名上传、下载等请求的安全性。
  • 如果您一定要使用永久密钥来生成预签名,建议永久密钥的权限范围仅限于上传或下载操作,以规避风险。(永久签名方法这里暂不提供需要留言或者去官方文档看)
  • 获取签名/预签名函数,默认签入 Header Host;您也可以选择不签入 Header Host,但可能导致请求失败或安全漏洞。
  • 引入依赖
  •     <dependencies>
            <!--腾讯云 COS-->
            <dependency>
                <groupId>com.qcloud</groupId>
                <artifactId>cos_api</artifactId>
                <version>${qcloud.cos.version}</version>
            </dependency>
            <!--腾讯云 COS 临时秘钥生成-->
            <dependency>
                <groupId>com.qcloud</groupId>
                <artifactId>cos-sts_api</artifactId>
                <version>${cos.sts.version}</version>
            </dependency>
        </dependencies>

package com.qpyx.oss.utils;

import com.tencent.cloud.CosStsClient;
import com.tencent.cloud.Response;

import java.util.TreeMap;

public class TemporarySecretKey {
    /**
     * 获取临时密钥
     * */
    public static Response getTemporarySecretKey (){
        TreeMap<String, Object> config = new TreeMap<String, Object>();

        try {
            //这里的 SecretId 和 SecretKey 代表了用于申请临时密钥的永久身份(主账号、子账号等),子账号需要具有操作存储桶的权限。
            // 替换为您的云 api 密钥 SecretId
            config.put("secretId", "这里填你自己储存桶 SecretId");
            // 替换为您的云 api 密钥 SecretKey
            config.put("secretKey", "这里填你自己储存桶 SecretKey");

            // 设置域名:
            // 如果您使用了腾讯云 cvm,可以设置内部域名
            //config.put("host", "sts.internal.tencentcloudapi.com");

            // 临时密钥有效时长,单位是秒,默认 1800 秒,目前主账号最长 2 小时(即 7200 秒),子账号最长 36 小时(即 129600)秒  这里设置60秒
            config.put("durationSeconds", 60);

            // 换成您的 bucket  例如  test-1300632903 
            config.put("bucket", "这里填你的桶名称");
            // 换成 bucket 所在地区
            config.put("region", "ap-guangzhou");

            // 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径
            // 列举几种典型的前缀授权场景:
            // 1、允许访问所有对象:"*"
            // 2、允许访问指定的对象:"a/a1.txt", "b/b1.txt"
            // 3、允许访问指定前缀的对象:"a*", "a/*", "b/*"
            // 如果填写了“*”,将允许用户访问所有资源;除非业务需要,否则请按照最小权限原则授予用户相应的访问权限范围。
            config.put("allowPrefixes", new String[] {
                    "a*"
            });

            // 密钥的权限列表。必须在这里指定本次临时密钥所需要的权限。
            // 简单上传、表单上传和分块上传需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
            String[] allowActions = new String[] {
                    // 简单上传
                    "name/cos:PutObject",
                    // 表单上传、小程序上传
                    "name/cos:PostObject",
                    // 分块上传
                    "name/cos:InitiateMultipartUpload",
                    "name/cos:ListMultipartUploads",
                    "name/cos:ListParts",
                    "name/cos:UploadPart",
                    "name/cos:CompleteMultipartUpload"
            };
            config.put("allowActions", allowActions);

            return CosStsClient.getCredential(config);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException("no valid secret !");
        }
    }

}

2.引入签名sdk

使用腾讯云对象存储(Cloud Object Storage,COS)时,可通过 RESTful API 对 COS 发起 HTTP 匿名请求或 HTTP 签名请求,对于签名请求,COS 服务器端将会进行对请求发起者的身份验证。

  • 匿名请求:HTTP 请求不携带任何身份标识和鉴权信息,通过 RESTful API 进行 HTTP 请求操作。
  • 签名请求:HTTP 请求时携带签名,COS 服务器端收到消息后,进行身份验证,验证成功则可接受并执行请求,否则将会返回错误信息并丢弃此请求。
package com.qpyx.oss.utils;


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;


/**
 *签名生成工具
 * */
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("response-cache-control");
        needSignedHeaderSet.add("response-content-disposition");
        needSignedHeaderSet.add("response-content-encoding");
        needSignedHeaderSet.add("response-content-language");
        needSignedHeaderSet.add("response-content-type");
        needSignedHeaderSet.add("response-expires");
        needSignedHeaderSet.add("transfer-encoding");
        needSignedHeaderSet.add("versionid");
    }

    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 头部 都要进行字符串排序
        TreeMap<String, String> sortedSignHeaders = new TreeMap<>();
        TreeMap<String, String> sortedParams = new TreeMap<>();

        sortedSignHeaders.putAll(signHeaders);
        sortedParams.putAll(paramMap);

        String qHeaderListStr = buildSignMemberStr(sortedSignHeaders);
        String qUrlParamListStr = buildSignMemberStr(sortedParams);
        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(sortedParams);
        String formatHeaders = formatMapToStr(sortedSignHeaders);

        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 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(UrlEncoderUtils.encode(key).toLowerCase());
        }
        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();
            String encodeKey = UrlEncoderUtils.encode(key);
            String lowerEncodeKey = encodeKey.toLowerCase();
            String encodedValue = "";
            if (value != null) {
                encodedValue = UrlEncoderUtils.encode(value);
            }
            if (!seeOne) {
                seeOne = true;
            } else {
                strBuilder.append("&");
            }
            strBuilder.append(lowerEncodeKey).append("=").append(encodedValue);
        }
        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;
    }
}

3.生成预上传url 和 生成预下载限速 url

第一步生成临时密钥后获取临时密钥id,key,token参数用来创建实例

创建好后生成预上传url  代码如下

package com.qpyx.oss.utils;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.Headers;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.BasicSessionCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import com.tencent.cloud.Response;

import java.net.URL;
import java.util.Date;


/**
 * 合同存储云策略
 */
public class ContractCloudStorage {
    // 创建 COSClient 实例,这个实例用来后续调用请求
    static COSClient createCOSClient() {
        // 这里需要已经获取到临时密钥的结果。
        Response temporarySecretKey = TemporarySecretKey.getTemporarySecretKey();
        String tmpSecretId = temporarySecretKey.credentials.tmpSecretId;
        String tmpSecretKey = temporarySecretKey.credentials.tmpSecretKey;
        String sessionToken = temporarySecretKey.credentials.sessionToken;

        COSCredentials cred = new BasicSessionCredentials(tmpSecretId, tmpSecretKey, sessionToken);

        // ClientConfig 中包含了后续请求 COS 的客户端设置:
        ClientConfig clientConfig = new ClientConfig();

        // 设置 bucket 的地域
        clientConfig.setRegion(new Region("ap-guangzhou"));

        // 设置请求协议, http 或者 https
        // 5.6.53 及更低的版本,建议设置使用 https 协议
        // 5.6.54 及更高版本,默认使用了 https
        clientConfig.setHttpProtocol(HttpProtocol.https);

        // 以下的设置,是可选的:

        // 设置 socket 读取超时,默认 30s
        clientConfig.setSocketTimeout(30*1000);
        // 设置建立连接超时,默认 30s
        clientConfig.setConnectionTimeout(30*1000);

        // 如果需要的话,设置 http 代理,ip 以及 port
        clientConfig.setHttpProxyIp("httpProxyIp");
        clientConfig.setHttpProxyPort(80);

        // 生成 cos 客户端。
        return new COSClient(cred, clientConfig);
    }
    /**
     * 生成预下载  限速
     * */
    public static String GenerateSimplePreSignedDownloadUrl(String key) {

        // 1 初始化用户身份信息(secretId, secretKey) 这里填你自己的
        COSCredentials cred = new BasicCOSCredentials("secretId", "secretKey");
        // 2 设置bucket的区域, COS地域的简称请参照官方文档
        ClientConfig clientConfig = new ClientConfig(new Region("ap-guangzhou"));
        // 如果要获取 https 的 url 则在此设置,否则默认获取的是 http url
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 3 生成cos客户端
        COSClient cosclient = new COSClient(cred, clientConfig);
        // bucket名需包含appid 这里填自己的桶名
        String bucketName = "bucketName";
        GeneratePresignedUrlRequest req =
                new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
        // 设置签名过期时间(可选), 若未进行设置则默认使用ClientConfig中的签名过期时间(30分钟)
        // 这里设置签名在一分钟后过期
        Date expirationDate = new Date(System.currentTimeMillis() +  60 * 1000);
        req.setExpiration(expirationDate);

        // 填写本次请求的参数
        // 设定限速值,这里限速10M/s
        req.addRequestParameter("x-cos-traffic-limit", "8388608");

        // 填写本次请求的头部。Host 必填
        req.putCustomRequestHeader(Headers.HOST,
                cosclient.getClientConfig().getEndpointBuilder().buildGeneralApiEndpoint(bucketName));
        //req.putCustomRequestHeader("header1", "value1");

        URL url = cosclient.generatePresignedUrl(req);
        cosclient.shutdown();
        return url.toString();
    }


    /**
     * 生成预签名  +  生成预下载覆盖头部
     * */
    public static Map<String,String> generatePreSignedUrl(String bucketName, String key, HttpMethodName method) throws CosClientException{
        // 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例,如果没有则创建
        COSClient cosClient = createCOSClient();
        // 存储桶的命名格式为 BucketName-APPID,此处填写的存储桶名称必须为此格式
        // 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
        // 设置签名过期时间(可选), 若未进行设置则默认使用 ClientConfig 中的签名过期时间(5分钟)
        // 这里设置签名在半个小时后过期
        Date expirationDate = new Date(System.currentTimeMillis() +  60 * 5000);
        // 填写本次请求的参数,需与实际请求相同,能够防止用户篡改此签名的 HTTP 请求的参数  没有不填之
        Map<String, String> params = new HashMap<String, String>();
        // 填写本次请求的头部,需与实际请求相同,能够防止用户篡改此签名的 HTTP 请求的头部 没有不填之
        Map<String, String> headers = new HashMap<String, String>();

        // 请求的 HTTP 方法,上传请求用 PUT,下载请求用 GET,删除请求用 DELETE
        URL url = cosClient.generatePresignedUrl(bucketName, key, expirationDate, method, headers, params);
        GeneratePresignedUrlRequest req =
                new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
        // 确认本进程不再使用 cosClient 实例之后,关闭之
        cosClient.shutdown();
        String generatePreSignedUrl = generatePreSignedUrl(req);
        Map<String, String> result = new HashMap<String, String>();
        result.put("url",url.toString());
        result.put("resultUrl",generatePreSignedUrl);
        return result;
    }

/**
     * 生成预下载覆盖头部
     * */
    public static  String generatePreSignedUrl(GeneratePresignedUrlRequest req) throws CosClientException{

        COSClient cosClient = createCOSClient();


        // 设置下载时返回的 http 头
        ResponseHeaderOverrides responseHeaders = new ResponseHeaderOverrides();
        String responseContentType = req.getContentType();
        String responseContentLanguage = "zh-CN";
        // 设置返回头部里包含文件名信息
        String responseContentDispositon = "filename=\""+req.getKey()+"\"";
        String responseCacheControl = "no-cache";
        String cacheExpireStr =
                DateUtils.formatRFC822Date(new Date(System.currentTimeMillis() + 24L * 3600L * 1000L));
        responseHeaders.setContentType(responseContentType);
        responseHeaders.setContentLanguage(responseContentLanguage);
        responseHeaders.setContentDisposition(responseContentDispositon);
        responseHeaders.setCacheControl(responseCacheControl);
        responseHeaders.setExpires(cacheExpireStr);

        req.setResponseHeaders(responseHeaders);

        // 设置签名过期时间(可选),若未进行设置,则默认使用 ClientConfig 中的签名过期时间(1分钟)
        // 这里设置签名在半个小时后过期
        Date expirationDate = new Date(System.currentTimeMillis() +  60L * 1000L);
        req.setExpiration(expirationDate);

        // 填写本次请求的头部
        // host 必填
        req.putCustomRequestHeader(Headers.HOST, cosClient.getClientConfig().getEndpointBuilder().buildGeneralApiEndpoint(req.getBucketName()));


        URL url = cosClient.generatePresignedUrl(req);
        System.out.println(url.toString());

        // 确认本进程不再使用 cosClient 实例之后,关闭之
        cosClient.shutdown();
        return url.toString();
    }

    /**
     * 生成签名 URL
     * */
    public static String getSignature() throws CosClientException{
        // 这里需要已经获取到临时密钥的结果。
        Response temporarySecretKey = TemporarySecretKey.getTemporarySecretKey();
        String tmpSecretId = temporarySecretKey.credentials.tmpSecretId;
        String tmpSecretKey = temporarySecretKey.credentials.tmpSecretKey;
        String sessionToken = temporarySecretKey.credentials.sessionToken;
        COSCredentials cred = new BasicSessionCredentials(tmpSecretId, tmpSecretKey, sessionToken);

        // 存储桶的命名格式为 BucketName-APPID,此处填写的存储桶名称必须为此格式
        String bucketName = "qipa-contract-***3";
        // 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
        String key = "contractExampleObject";
        //若key不是以“/”开头,则需要在key的开头加上“/”,否则直接resource_path=key
        String resource_path="/" + key;

        ClientConfig clientConfig = new ClientConfig(new Region("ap-guangzhou"));

        // 用来生成签名
        COSSigner signer = new COSSigner();
        // 设置签名过期时间(可选),若未进行设置,则默认使用 ClientConfig 中的签名过期时间(5分钟)
        // 这里设置签名在半个小时后过期
        Date expirationDate = new Date(System.currentTimeMillis() +  60L * 5000L);

        // 填写本次请求的参数
        Map<String, String> params = new HashMap<String, String>();
        params.put("param1", "value1");

        // 填写本次请求的头部
        Map<String, String> headers = new HashMap<String, String>();
        // host 必填
        headers.put(Headers.HOST, clientConfig.getEndpointBuilder().buildGeneralApiEndpoint(bucketName));
        headers.put("header1", "value1");
        // 请求的 HTTP 方法,上传请求用 PUT,下载请求用 GET,删除请求用 DELETE
        HttpMethodName method = HttpMethodName.GET;
        String sign = signer.buildAuthorizationStr(method, resource_path, headers, params, cred, expirationDate, true);
        return sign;
    }

   
}

4.生成上传url后可通过url上传文件到桶内!注意上传为put请求

    /**
     * 上传图片
     * @param file
     * @return
     */
    @Override
    public boolean upload(Integer id,MultipartFile file) {
        String originalfileName = file.getOriginalFilename();
        String[] split = originalfileName.split("\\.");
           //防止名称重复随机生成序列号
        String path = getPath(split[1]);
        //这里调用之前封装的接口  第二个参数为上传桶内的路径+文件名 签名放行了a*的所有路径所有a开头文件夹按年月分层级上传  注意文件名要带文件类型后缀例如aa.jpg 等  
        Map<String, String> signMap = ContractCloudStorage.generatePreSignedUrl("自己的桶名", "a/"+ path, HttpMethodName.PUT);
        String url = signMap.get("url");
//这里的k 可以入库存起来 因为后续下载需要用到 根据k生成临时的下载链接 
        String key = "contract/"+ path;
        try {
             upLoadFileByFile(url, file);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


 /**
     *
     * 根据临时签名 上传文件
     * */
    public static int upLoadFileByFile(String singnedurl,MultipartFile file)  throws Exception{
        URL url=new URL(singnedurl);
        InputStream inputStream = file.getInputStream();

        int responseCode = 0;
        try {
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setRequestMethod("PUT");
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());

            //out=new OutputStreamWriter(new FileOutputStream(new File("c:/qqq.zip")));
            // 写入要上传的数据
            byte buff[]= new byte[1024];
            int len;
            while( (len=inputStream.read(buff))!=-1  ) {
                out.write(buff, 0, len);
            }
            out.close();
            responseCode = connection.getResponseCode();
            log.info("Service returned response code " + responseCode);
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return responseCode;
    }

    
       //生成路径
    public String getPath(String suffix) {
        //获取年月
        String time = DateUtil.format(DateUtil.date(), "yyyyMM");
        // 生成uuid
        String uuid = IdUtil.fastSimpleUUID();
        // 文件路径
        String path = time + "/" + uuid;
        return path + "."+suffix;
    }

5.文件下载

文件下载统一用get请求这里调用上面封装的方法

    /**
     * 获取合同下载地址
     *
     * @param key  对象key  这里的k就是上传时候的文件路径
     * @return url
     */
    @Override
    public AjaxResult download(String key) {
        String url = ContractCloudStorage.GenerateSimplePreSignedDownloadUrl(key);
        return AjaxResult.success("操作成功",url);
    }

整个上传下载流程就完成啦!这里生成的url地址有效期都是一分钟因为前面有设置,每次要获取下载地址需要根据桶内对象k调用下载接口生成下载ur地址,过期自动失效非常安全!!。

不懂得可以留言。

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值