当前位置: 首页 > news >正文

使用STS以及签名URL临时授权访问OSS资源

本文介绍JAVA如何使用STS以及签名URL临时授权访问OSS资源。

注意事项

  • 由于STS临时账号以及签名URL均需设置有效时长,当您使用STS临时账号生成签名URL执行相关操作(例如上传、下载文件)时,以最小的有效时长为准。例如您的STS临时账号的有效时长设置为1200秒、签名URL设置为3600秒时,当有效时长超过1200秒后,您无法使用此STS临时账号生成的签名URL上传文件。

  • 本文以从环境变量读取访问凭证为例。如何配置访问凭证,请参见配置访问凭证。

  • 本文以华东1(杭州)的外网Endpoint为例。如果您希望通过与OSS同地域的其他阿里云产品访问OSS,请使用格式为https://oss-cn-hangzhou-internal.aliyuncs.com的内网Endpoint。关于OSS支持的Region与Endpoint的对应关系,请参见访问域名和数据中心。

  • 本文以使用OSS外网Endpoint新建OSSClient为例。如果您希望通过自定义域名、STS等方式新建OSSClient,请参见新建OSSClient。

使用STS进行临时授权

OSS可以通过阿里云STS(Security Token Service)进行临时授权访问。阿里云STS是为云计算用户提供临时访问令牌的Web服务。通过STS,您可以为第三方应用或子用户(即用户身份由您自己管理的用户)颁发一个自定义时效和权限的访问凭证。关于STS的更多信息,请参见STS介绍。

STS的优势如下:

  • 您无需透露您的长期密钥(AccessKey)给第三方应用,只需生成一个访问令牌并将令牌交给第三方应用。您可以自定义这个令牌的访问权限及有效期限。

  • 您无需关心权限撤销问题,访问令牌过期后自动失效。

通过STS临时授权访问OSS的步骤如下:

  1. 获取临时访问凭证

    临时访问凭证包括临时访问密钥(AccessKey ID和AccessKey Secret)和安全令牌(SecurityToken)。临时访问凭证有效时间单位为秒,最小值为900,最大值以当前角色设定的最大会话时间为准。更多信息,请参见设置RAM角色最大会话时间。

    您可以通过以下两种方式获取临时访问凭证。

    • 方式一

      通过调用STS服务的AssumeRole接口获取临时访问凭证。

    • 方式二

      通过各语言STS SDK获取临时访问凭证。

  2. 使用STS临时授权上传和下载文件。

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.model.GetObjectRequest;
    import com.aliyun.oss.model.PutObjectRequest;
    import java.io.File;public class Demo {public static void main(String[] args) throws Throwable {// 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";// 从环境变量中获取从STS服务请求返回的临时访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID、OSS_ACCESS_KEY_SECRET以及OSS_SESSION_TOKEN。EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName = "exampleobject.txt";// 填写本地文件完整路径。String pathName = "D:\\localpath\\examplefile.txt";// 从STS服务获取临时访问凭证后,您可以通过临时访问密钥和安全令牌生成OSSClient。// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);try {            // 上传文件,此处以上传本地文件为例。            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(pathName));ossClient.putObject(putObjectRequest);// 下载OSS文件到本地文件。如果指定的本地文件存在则覆盖,不存在则新建。            //ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(pathName));} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}
    }

使用签名URL进行临时授权

注意事项

  • 生成签名URL过程中,SDK利用本地存储的密钥信息,根据特定算法计算出签名(signature),然后将其附加到URL上,以确保URL的有效性和安全性。这一系列计算和构造URL的操作都是在客户端完成,不涉及网络请求到服务端。因此,生成签名URL时不需要授予调用者特定权限。但是,为避免第三方用户无法对签名URL授权的资源执行相关操作,需要确保调用生成签名URL接口的身份主体被授予对应的权限。

    例如,通过签名URL上传文件时,需要授予oss:PutObject权限。通过签名URL下载或预览文件时,需要授予oss:GetObject权限。

  • 您可以将生成的签名URL提供给访客进行临时访问。生成签名URL时,您可以自定义URL的过期时间来限制访客的访问时长。

  • 如果需要生成HTTPS协议的签名URL,请将Endpoint中的通信协议设置为HTTPS。

  • 通过以下示例生成的签名URL中如果包含特殊符号+,可能出现无法正常访问该签名URL的现象。如需正常访问该签名URL,请将签名URL中的+替换为%2B

以下是使用签名URL临时授权的常见示例。

生成以GET方法访问的签名URL

以下代码用于生成以GET方法访问的签名URL。

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import java.net.URL;
import java.util.Date;
import java.util.Date;public class Demo {public static void main(String[] args) throws Throwable {// 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName = "exampleobject.txt";// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);try {// 设置签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。Date expiration = new Date(new Date().getTime() + 3600 * 1000L);// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);System.out.println(url);} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}
}

生成以其他HTTP方法访问的签名URL

如果您要授权其他用户临时执行其他操作(例如上传、删除文件等),需要生成对应的签名URL,例如生成以PUT方法访问的签名URL来上传文件。

以下代码用于生成以其他HTTP方法访问的签名URL。

import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.utils.HttpHeaders;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import java.io.ByteArrayInputStream;
import java.net.URL;
import java.util.*;
import java.util.Date;import static com.aliyun.oss.internal.OSSHeaders.OSS_USER_METADATA_PREFIX;public class Demo {public static void main(String[] args) throws Throwable {// 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName = "exampleobject.txt";// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);try {GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);// 设置签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。Date expiration = new Date(new Date().getTime() + 3600 * 1000L);request.setExpiration(expiration);// 设置ContentType。request.setContentType("text/plain");// 设置自定义元数据。request.addUserMetadata("author", "aliy");// 生成签名URL。URL signedUrl = ossClient.generatePresignedUrl(request);System.out.println(signedUrl);Map<String, String> requestHeaders = new HashMap<String, String>();// 设置ContentType,必须和生成签名URL时设置的ContentType一致。requestHeaders.put(HttpHeaders.CONTENT_TYPE, "text/plain");// 设置自定义元数据。requestHeaders.put(OSS_USER_METADATA_PREFIX + "author", "aliy");// 使用签名URL上传文件。ossClient.putObject(signedUrl, new ByteArrayInputStream("Hello OSS".getBytes()), -1, requestHeaders, true);} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}
}      

通过传入HttpMethod.PUT参数,访客可以使用生成的签名URL上传文件。

生成带有指定参数的签名URL

  • 生成带有指定参数的签名URL

    以下代码用于生成带有指定参数的签名URL。

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    import java.net.URL;
    import java.util.*;
    import java.util.Date;public class Demo {public static void main(String[] args) throws Throwable {// 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName = "exampleobject.txt";// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);try {// 创建请求。GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objectName);// 设置HttpMethod为PUT。generatePresignedUrlRequest.setMethod(HttpMethod.PUT);// 添加用户自定义元数据。generatePresignedUrlRequest.addUserMetadata("author", "baymax");// 设置ContentType。generatePresignedUrlRequest.setContentType("application/txt");// 设置签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。Date expiration = new Date(new Date().getTime() + 3600 * 1000L);generatePresignedUrlRequest.setExpiration(expiration);// 生成签名URL。URL url = ossClient.generatePresignedUrl(generatePresignedUrlRequest);System.out.println(url);} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}
    }
  • 生成带有versionId的签名URL

    以下代码用于生成带有versionId的签名URL。

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    import java.net.URL;
    import java.util.*;
    import java.util.Date;public class Demo {public static void main(String[] args) throws Throwable {// 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName = "exampleobject.txt";// 填写Object的versionId。String versionId = "CAEQARiBgID8rumR2hYiIGUyOTAyZGY2MzU5MjQ5ZjlhYzQzZjNlYTAyZDE3****";// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);try {// 创建请求。GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objectName);// 设置HttpMethod为GET。generatePresignedUrlRequest.setMethod(HttpMethod.GET);// 设置签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。Date expiration = new Date(new Date().getTime() + 3600 * 1000L);generatePresignedUrlRequest.setExpiration(expiration);// Object的versionId。Map<String, String> queryParam = new HashMap<String, String>();queryParam.put("versionId", versionId);generatePresignedUrlRequest.setQueryParameter(queryParam);// 生成签名URL。URL url = ossClient.generatePresignedUrl(generatePresignedUrlRequest);System.out.println(url);} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}}
    }

使用签名URL临时授权上传或下载文件

  • 使用签名URL上传文件

    以下代码用于生成上传的签名URL,并使用签名URL临时授权简单上传文件。

    说明

    您也可以先生成签名URL后再通过该URL临时授权简单上传文件。关于如何生成签名URL,请参见URL签名。

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    import com.aliyun.oss.model.StorageClass;
    import org.apache.http.HttpEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPut;
    import org.apache.http.entity.FileEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import java.io.*;
    import java.net.URL;
    import java.util.*;
    import java.util.Date;public class Demo {public static void main(String[] args) throws Throwable {// 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName = "exampleobject.txt";// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。String pathName = "D:\\localpath\\examplefile.txt";// 创建OSSClient实例OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);// 设置请求头。Map<String, String> headers = new HashMap<String, String>();/*// 指定Object的存储类型。headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());// 指定ContentType。headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/// 设置用户自定义元数据。Map<String, String> userMetadata = new HashMap<String, String>();/*userMetadata.put("key1","value1");userMetadata.put("key2","value2");*/URL signedUrl = null;try {// 指定生成的签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。Date expiration = new Date(new Date().getTime() + 3600 * 1000L);// 生成签名URL。GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.PUT);// 设置过期时间。request.setExpiration(expiration);// 将请求头加入到request中。request.setHeaders(headers);// 添加用户自定义元数据。request.setUserMetadata(userMetadata);// 通过HTTP PUT请求生成签名URL。signedUrl = ossClient.generatePresignedUrl(request);// 打印签名URL。System.out.println("signed url for putObject: " + signedUrl);} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());}// 通过签名URL临时授权简单上传文件,以HttpClients为例说明。putObjectWithHttp(signedUrl, pathName, headers, userMetadata);}public static void putObjectWithHttp(URL signedUrl, String pathName, Map<String, String> headers, Map<String, String> userMetadata) throws IOException {CloseableHttpClient httpClient = null;CloseableHttpResponse response = null;try {HttpPut put = new HttpPut(signedUrl.toString());HttpEntity entity = new FileEntity(new File(pathName));put.setEntity(entity);// 如果生成签名URL时设置了header参数,例如用户元数据,存储类型等,则调用签名URL上传文件时,也需要将这些参数发送至服务端。如果签名和发送至服务端的不一致,会报签名错误。for(Map.Entry header: headers.entrySet()){put.addHeader(header.getKey().toString(),header.getValue().toString());}for(Map.Entry meta: userMetadata.entrySet()){// 如果使用userMeta,sdk内部会为userMeta拼接"x-oss-meta-"前缀。当您使用其他方式生成签名URL进行上传时,userMeta也需要拼接"x-oss-meta-"前缀。put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());}httpClient = HttpClients.createDefault();response = httpClient.execute(put);System.out.println("返回上传状态码:"+response.getStatusLine().getStatusCode());if(response.getStatusLine().getStatusCode() == 200){System.out.println("使用网络库上传成功");}System.out.println(response.toString());} catch (Exception e){e.printStackTrace();} finally {response.close();httpClient.close();}}
    }       
  • 使用签名URL临时授权分片上传

    当您希望使用签名URL以分片上传的方式上传大文件到OSS时,您需要先初始化分片上传,然后把每一个分片生成一个对应的上传签名URL,并返回给第三方应用。第三方应用可以使用这些签名URL上传所有的分片信息,然后合并分片来达到通过签名URL实现分片上传的目的。

    以下代码用于生成分片上传的签名URL,并使用签名URL临时授权分片上传。

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.common.comm.io.BoundedInputStream;
    import com.aliyun.oss.common.utils.BinaryUtil;
    import com.aliyun.oss.common.utils.CRC64;
    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.*;
    import org.apache.commons.codec.digest.DigestUtils;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPut;
    import org.apache.http.entity.BufferedHttpEntity;
    import org.apache.http.entity.InputStreamEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
    import org.apache.http.impl.client.HttpClients;
    import java.io.*;
    import java.math.BigInteger;
    import java.net.URL;
    import java.util.*;
    import java.util.Date;
    import java.util.zip.CheckedInputStream;public class SignUrlMultipart {public static void main(String[] args) throws Throwable {// 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName = "exampleobject.txt";// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。String pathName = "D:\\localpath\\examplefile.txt";// 指定生成的签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。long expireTime = 3600*1000L;// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);// 创建InitiateMultipartUploadRequest对象。InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(bucketName, objectName);// 初始化分片。InitiateMultipartUploadResult upResult = ossClient.initiateMultipartUpload(initRequest);// 返回uploadId。uploadId是分片上传事件的唯一标识。您可以根据该uploadId发起相关的操作,例如取消分片上传、查询分片上传等。String uploadId = upResult.getUploadId();// partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。List<PartETag> partETags =  new ArrayList<PartETag>();// 每个分片的大小,用于计算文件有多少个分片。单位为字节。long partSize = 1 * 100 * 1024L;   //100kb。// 填写本地文件的完整路径。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。File sampleFile = new File(pathName);long fileLength = sampleFile.length();// 如果希望设置为1个分片,可以将分片大小设置为文件大小。// long fileLength = sampleFile.length();int partCount = (int) (fileLength / partSize);if (fileLength % partSize != 0) {partCount++;}// 设置签名URL的请求头。Map<String, String> headers = new HashMap<String, String>();/*// 指定Object的存储类型。headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());// 指定ContentType。headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/// 遍历分片获取分片签名,并上传分片。// 您还可以一次返回所有分片的签名URL,然后依次上传。此处以返回单个签名URL,并通过签名URL上传单个分片为例。for (int i = 0; i < partCount; i++) {long startPos = i * partSize;long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;/*// 设置md5校验,只支持对单个分片进行md5校验FileInputStream inStream = new FileInputStream(pathName);// 跳过已经上传的分片。inStream.skip(startPos);BoundedInputStream entity = new BoundedInputStream(inStream, partSize);String md5 = BinaryUtil.toBase64String(DigestUtils.md5(entity));headers.put("Content-MD5", md5);*/String signUrl = getSignUrl(ossClient, bucketName, objectName, HttpMethod.PUT, expireTime, i + 1, uploadId, headers);// 通过签名URL上传文件,以HttpClients为例说明。putObjectWithHttp(signUrl, pathName, startPos, curPartSize, headers);}// 假设合并分片时,与上传分片不在同一个系统。此时,您需要先列举分片,然后再合并分片。// 列举已上传的分片。ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, objectName, uploadId);PartListing partListing = ossClient.listParts(listPartsRequest);// 遍历分片,并填充partETags。for (PartSummary part : partListing.getParts()) {PartETag partETag = new PartETag(part.getPartNumber(), part.getETag());partETags.add(partETag);}// 合并分片。CompleteMultipartUploadRequest completeMultipartUploadRequest =new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);// String md5 = BinaryUtil.toBase64String(BinaryUtil.calculateMd5("aaa".getBytes()));// 设置禁止覆盖同名文件。// completeMultipartUploadRequest.addHeader("x-oss-forbid-overwrite", "true");// 完成分片上传。CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);System.out.println("合并分片成功,上传分片完成。");// 校验整体上传文件是否完整CRC64 crc = new CRC64();InputStream inStream = new FileInputStream(pathName);byte[] bytes = new byte[1024];int cnt;while ((cnt = inStream.read(bytes)) != -1) {crc.update(bytes, 0, cnt);}if(crc.getValue() == completeMultipartUploadResult.getServerCRC()){System.out.println("上传文件完整");} else {System.out.println("上传文件不完整,请做异常处理");}}public static void putObjectWithHttp(String signedUrl, String pathName, long startPos, long partSize, Map<String, String> headers) throws IOException {CloseableHttpClient httpClient = null;CloseableHttpResponse response = null;try {HttpPut put = new HttpPut(signedUrl);FileInputStream inStream = new FileInputStream(pathName);// 跳过已经上传的分片。inStream.skip(startPos);InputStreamEntity entity = new InputStreamEntity(inStream, partSize);BufferedHttpEntity byteArrayEntity = new BufferedHttpEntity(entity);put.setEntity(byteArrayEntity);// 如果生成签名URL时设置了header参数,例如用户元数据,存储类型等,则调用签名URL上传文件时,也需要将这些参数发送至服务端。如果签名和发送至服务端的不一致,会报签名错误。for(Map.Entry header: headers.entrySet()){put.addHeader(header.getKey().toString(),header.getValue().toString());}// 加入重试,设置为重试3次。这里仅为举例,业务代码根据需要自行设置重试httpClient = HttpClients.custom().setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)).build();response = httpClient.execute(put);System.out.println("返回上传状态码:"+response.getStatusLine().getStatusCode());if(response.getStatusLine().getStatusCode() == 200){System.out.println("使用网络库上传成功");}System.out.println(response.toString());} catch (Exception e){e.printStackTrace();} finally {if(response != null){response.close();}if(httpClient != null){httpClient.close();}}}public static String getSignUrl(OSS ossClient, String bucketName, String objectName, HttpMethod method, long expireTime, int partNum, String uploadId, Map<String, String> headers){// 指定生成的签名URL过期时间,单位为毫秒。Date expiration = new Date(new Date().getTime() + expireTime);// 生成签名URL。GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, method);// 设置过期时间。request.setExpiration(expiration);// 将请求头加入到request中。request.setHeaders(headers);request.addQueryParameter("partNumber", String.valueOf(partNum));request.addQueryParameter("uploadId", uploadId);// 通过HTTP Method请求生成签名URL。URL signedUrl = ossClient.generatePresignedUrl(request);// 打印签名URL。System.out.println("signed url: " + signedUrl);return signedUrl.toString();}
    }
  • 使用签名URL临时授权下载文件

    以下代码用于生成下载的签名URL,并使用签名URL临时授权下载文件。

    import com.aliyun.oss.*;
    import com.aliyun.oss.common.auth.*;
    import com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.GeneratePresignedUrlRequest;
    import com.aliyun.oss.model.StorageClass;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import java.io.*;
    import java.net.URL;
    import java.util.*;
    import java.util.Date;public class Demo {public static void main(String[] args) throws Throwable {// 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();// 填写Bucket名称,例如examplebucket。String bucketName = "examplebucket";// 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。String objectName = "exampleobject.txt";// 填写下载到本地文件的完整路径。String pathName = "D:\\localpath\\examplefile.txt";// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);// 设置请求头。Map<String, String> headers = new HashMap<String, String>();/*// 指定Object的存储类型。headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());// 指定ContentType。headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/// 设置用户自定义元数据。Map<String, String> userMetadata = new HashMap<String, String>();/*userMetadata.put("key1","value1");userMetadata.put("key2","value2");*/URL signedUrl = null;try {// 指定生成的签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。Date expiration = new Date(new Date().getTime() + 3600 * 1000L);// 生成签名URL。GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.GET);// 设置过期时间。request.setExpiration(expiration);// 将请求头加入到request中。request.setHeaders(headers);// 添加用户自定义元数据。request.setUserMetadata(userMetadata);// 设置查询参数。// Map<String, String> queryParam = new HashMap<String, String>();// 指定IP地址或者IP地址段,对应日志中sourceIpFromSource的值。// queryParam.put("x-oss-ac-source-ip","192.0.2.0");// 将子网掩码转换为二进制,然后填写转换结果中1的数量。// queryParam.put("x-oss-ac-subnet-mask","32");// 指定VPC ID。// queryParam.put("x-oss-ac-vpc-id","vpc-12345678");// 指定是否允许转发请求。// queryParam.put("x-oss-ac-forward-allow","true");// request.setQueryParameter(queryParam);// 设置单链接限速,单位为bit,例如限速100 KB/s。// request.setTrafficLimit(100 * 1024 * 8);// 通过HTTP GET请求生成签名URL。signedUrl = ossClient.generatePresignedUrl(request);// 打印签名URL。System.out.println("signed url for putObject: " + signedUrl);} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());}// 通过签名URL下载文件,以HttpClients为例说明。getObjectWithHttp(signedUrl, pathName, headers, userMetadata);}public static void getObjectWithHttp(URL signedUrl, String pathName, Map<String, String> headers, Map<String, String> userMetadata) throws IOException {CloseableHttpClient httpClient = null;CloseableHttpResponse response = null;try {HttpGet get = new HttpGet(signedUrl.toString());// 如果生成签名URL时设置了header参数,例如用户元数据,存储类型等,则调用签名URL下载文件时,也需要将这些参数发送至服务端。如果签名和发送至服务端的不一致,会报签名错误。for(Map.Entry header: headers.entrySet()){get.addHeader(header.getKey().toString(),header.getValue().toString());}for(Map.Entry meta: userMetadata.entrySet()){// 如果使用userMeta,sdk内部会为userMeta拼接"x-oss-meta-"前缀。当您使用其他方式生成签名URL进行下载时,userMeta也需要拼接"x-oss-meta-"前缀。get.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());}httpClient = HttpClients.createDefault();response = httpClient.execute(get);System.out.println("返回下载状态码:"+response.getStatusLine().getStatusCode());if(response.getStatusLine().getStatusCode() == 200){System.out.println("使用网络库下载成功");}System.out.println(response.toString());// 保存文件到磁盘。saveFileToLocally(response.getEntity().getContent(), pathName);} catch (Exception e){e.printStackTrace();} finally {response.close();httpClient.close();}}public static void saveFileToLocally(InputStream inputStream, String pathName) throws IOException {DataInputStream in = null;OutputStream out = null;try {in = new DataInputStream(inputStream);out = new DataOutputStream(new FileOutputStream(pathName));int bytes = 0;byte[] bufferOut = new byte[1024];while ((bytes = in.read(bufferOut)) != -1) {out.write(bufferOut, 0, bytes);}} catch (Exception e){e.printStackTrace();} finally {in.close();out.close();}}
    }

常见问题

使用临时签名进行文件上传时,在上传过程中签名过期了,上传中的文件会失败吗?

简单上传时不会失败。

如果是分片上传,上传过程中签名过期了,可能影响其余分片的上传。

相关文章:

使用STS以及签名URL临时授权访问OSS资源

本文介绍JAVA如何使用STS以及签名URL临时授权访问OSS资源。 注意事项 由于STS临时账号以及签名URL均需设置有效时长&#xff0c;当您使用STS临时账号生成签名URL执行相关操作&#xff08;例如上传、下载文件&#xff09;时&#xff0c;以最小的有效时长为准。例如您的STS临时账…...

Next.js 14 使用 react-md-editor 编辑器 并更改背景颜色

1.简介 react-md-editor是一款markdown编辑器&#xff0c;本文介绍如何在Next.js中使用它。 2.安装 安装命令&#xff1a; npm install uiw/react-md-editor3.MD编辑器 markdown编辑器的使用&#xff1a; "use client" import MDEditor from uiw/react-md-edi…...

【Iceberg分析】Spark与Iceberg集成落地实践(一)

Spark与Iceberg集成落地实践&#xff08;一&#xff09; 文章目录 Spark与Iceberg集成落地实践&#xff08;一&#xff09;清理快照与元数据配置表维度自动清理元数据文件属性手动清理 清理孤岛文件合并数据文件 清理快照与元数据 配置表维度自动清理元数据文件属性 每一次写…...

【Verilog学习日常】—牛客网刷题—Verilog进阶挑战—VL45

异步FIFO 描述 请根据题目中给出的双口RAM代码和接口描述&#xff0c;实现异步FIFO&#xff0c;要求FIFO位宽和深度参数化可配置。 电路的接口如下图所示。 双口RAM端口说明&#xff1a; 端口名 I/O 描述 wclk input 写数据时钟 wenc input 写使能 waddr input 写…...

【强训笔记】day27

NO.1 代码实现&#xff1a; #include<iostream>using namespace std;int n,m; int main() {cin>>n>>m;long long retn;for(int i0;i<m-1;i)retret*(n-1)%109;cout<<ret<<endl;return 0; }NO.2 思路&#xff1a;bfs遍历实现&#xff0c;dis…...

Nginx06-静态资源部署

零、文章目录 Nginx06-静态资源部署 1、静态资源概述 静态资源&#xff1a;是在Web开发中不经常改变的文件&#xff0c;比如图片、CSS样式表、JavaScript脚本文件等。这些资源通常是预先编译好的&#xff0c;不需要服务器端的动态处理。动态资源&#xff1a;是在Web开发中需…...

MySQL数据库专栏(二)SQL语句基础操作

目录 数据库操作 创建数据库 查看数据库 选择数据库 删除数据库 数据表操作 数据表数据类型 数据表列约束 数据表索引 创建表 查看表 查看表结构 删除表 数据表的增删改操作 …...

【OpenCV 实战】1.手势虚拟拖拽(双手骨骼点识别)

step: 1.opencv 获取视频流 2.在画面上画一个方块 3.通过mediapipe获取手指关键点坐标 4.判断手指是否在方块上 5.若在方块上&#xff0c;方块跟着手指移动 mediapipe网站介绍&#xff1a;Hands - mediapipe (chuoling.github.io) 已上传到GitHub &#xff1a; plumqm/OpenC…...

基于springboot人力资源管理系统源码

项目技术&#xff1a;SpringBoot 运行环境&#xff1a;jdk1.8idea/eclipsemaven3mysql5.6 项目描述&#xff1a; 系统包括&#xff0c;员工管理&#xff0c;奖惩管理&#xff0c;合同管理&#xff0c;薪酬管理&#xff0c;培训管理&#xff0c;绩效评估等功能...

如何使用 Apt-Get 和 Apt-Cache 在 Ubuntu 和 Debian 中管理软件包

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 简介 Apt 是 dpkg 打包系统的命令行前端&#xff0c;也是许多发行版中管理软件的首选方式。它是 Debian 及基于 Debian 的 Linux 发行版…...

Linux系统创建新分区并挂载的方法

一、引言 本文以CentOS为例讲述Linux系统创建新分区并挂载的方法。如下图所示&#xff0c;用fdisk -l命令可以看到该CentOS系统下有一个磁盘/dev/vda&#xff0c;其容量为2199G&#xff0c;即2T。该磁盘有两个分区&#xff1a;vda1和vda2&#xff1a; 用lsblk命令可以查看到磁…...

反射第二弹:用注册器动态注册(用自定义的注解标注的)策略,实现策略模式的设计

目录 引言 设计思路: 代码实现: 标注注解:@StrategyClass 扫描注解:trategyScan 注册器抽象类: 动态策略注册类: AOP类: 总结: 引言 曾经有人问我,假如有一个业务或者数据处理逻辑,会根据甲方客户繁杂的业务需求,而动态变化,该怎么处理,具体怎么实现? 将…...

【Xcode Command Line Tools】安装指南

安装指令 xcode-select --install安装 完成安装 验证 $ xcode-select -p /Library/Developer/CommandLineTools...

springboot开发网站-使用redis数据库定时特征限制指定ip的访问次数

springboot开发网站-使用redis数据库定时特征限制指定ip的访问次数。近期网站经常有人恶意访问&#xff0c;提交了很多垃圾信息。为了屏蔽这类灌水帖&#xff0c;打算屏蔽ip地址&#xff0c;限制24小时内只能访问1次某个接口。下面是测试的案例代码内容。 1&#xff1a;首先&am…...

【大模型理论篇】大模型相关的周边技术分享-关于《NN and DL》的笔记

本文所要介绍的一本书《Neural Networks and Deep Learning》&#xff0c;该书作者Michael Nielsen&#xff0c;Y Combinator Research的研究员&#xff0c;是多年之前自己看的一本基础书籍&#xff0c;很适合入门了解一些关于深度学习的概念知识&#xff0c;当然也包含了一些小…...

CSS 圆形边框与阴影

目录 1. 圆角边框 1.1 正圆 1.2 圆角矩形 1.3 任意圆角 1.4 某个圆角 2. 盒子阴影 3. 文字阴影 1. 圆角边框 1.1 正圆 1.2 圆角矩形 1.3 任意圆角 1.4 某个圆角 2. 盒子阴影 3. 文字阴影...

Bianchi模型、python计算及ns3验证

由于项目与学习需要,最近学习了bianchi模型,并在python中进行了公式->代码的转化,仿真结果与ns3结果对比。 本文更多的是理解模型各个部分的含义、把各个简单的推导过程转化为python、ns3对比: 1 理论吞吐与传输概率、传输成功概率、包长、速率、排队时间、成功传输时…...

SQL常用语法

SQL&#xff08;Structured Query Language&#xff09;是一种用于存储、操作和检索数据库中数据的标准编程语言。以下是一些常用的 SQL 语法&#xff1a; 数据库操作 创建数据库&#xff1a;CREATE DATABASE database_name;删除数据库&#xff1a;DROP DATABASE database_name…...

计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…...

浏览器前端向后端提供服务

WEB后端向浏览器前端提供服务是最常见的场景&#xff0c;前端向后端的接口发起GET或者POST请求&#xff0c;后端收到请求后执行服务器端任务进行处理&#xff0c;完成后向前端发送响应。 那浏览器前端向后端提供服务是什么鬼&#xff1f; 说来话长&#xff0c;长话短说。我在人…...

文本到语音或视频的构想

₦X8s43Y1iIquVAeF₦ 在Python中&#xff0c;有几个库和模块可以用来实现文本到语音的转换&#xff0c;并且可以生成带有背景音乐的视频。以下是一些可用的库&#xff1a; 1. pyttsx3&#xff1a;这是一个离线文本到语音转换库&#xff0c;它支持多种语音引擎&#xff0c;不依…...

请解释一下数据库的分区和分片?请解释一下数据库的日志和日志的重要性?

请解释一下数据库的分区和分片&#xff1f; 数据库的分区和分片是两种用于提高数据库性能和可扩展性的技术&#xff0c;它们各自具有不同的特点和应用场景。以下是对这两种技术的详细解释&#xff1a; 一、数据库分区 定义&#xff1a; 数据库分区是将一个大型的数据库表或索…...

windows C++-创建数据流代理(二)

完整的数据流演示 下图显示了 dataflow_agent 类的完整数据流网络&#xff1a; 由于 run 方法是在一个单独的线程上调用的&#xff0c;因此在完全连接网络之前&#xff0c;其他线程可以将消息发送到网络。 _source 数据成员是一个 unbounded_buffer 对象&#xff0c;用于缓冲…...

大数据毕业设计选题推荐-个性化图书推荐系统-Python数据可视化-Hive-Hadoop-Spark

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇…...

【Redis入门到精通九】Redis中的主从复制

目录 主从复制 1.配置主从复制 2.主从复制中的拓扑结构 3.主从复制原理 4.主从复制总结 主从复制 在分布式系统中为了解决单点问题&#xff0c;通常会把数据复制多个副本部署到其他服务器&#xff0c;满⾜故障恢复和负载均衡等需求。Redis 也是如此&#xff0c;它为我们提…...

系统架构设计师论文《论企业应用系统的数据持久层架构设计》精选试读

论文真题 数据持久层&#xff08;Data Persistence Layer&#xff09;通常位于企业应用系统的业务逻辑层和数据源层之间&#xff0c;为整个项目提供一个高层、统一、安全、并发的数据持久机制&#xff0c;完成对各种数据进行持久化的编程工作&#xff0c;并为系统业务逻辑层提…...

策略模式和模板模式的区别

目录 一、实现方式 策略模式 模板模式 二、使用场景 三、优点 四、举例 一、实现方式 策略模式 定义策略接口 Strategy创建具体策略类 OperationAdd、OperationSubtract、OperationMultiply创建一个上下文类 Context&#xff0c;包含一个策略对象的引用&#xff0c;并通…...

【ubuntu】ubuntu20.04安装conda

1.下载 安装参考&#xff1a;https://blog.csdn.net/weixin_44119391/article/details/128577681 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 2.安装 sudo chmod 777 -R ./Anaconda3-5.3.1-Linux-x86_64.sh ./Anaconda3-5.3.1-Linux-x86_64.sh Enter键确认安装…...

使用 SAP ABAP Webdynpro 实现 ABAP Push Channel 的 Web Socket 客户端

本系列前三篇文章,笔者向大家介绍了基于 ABAP Push Channel(简称 APC)的 TCP Socket 服务器端和客户端的编程,以及 Web Socket 的服务器端实现。 使用 ABAP 实现 TCP Socket 编程 (1) - 客户端部分的实现使用 ABAP 实现 TCP Socket 编程 (2) - 服务器端部分的实现使用 ABAP 实…...

15分钟学 Python 第41天:Python 爬虫入门(六)第二篇

Day41&#xff1a;Python爬取猫眼电影网站的电影信息 1. 项目背景 在本项目中&#xff0c;我们将使用 Python 爬虫技术从猫眼电影网站抓取电影信息。猫眼电影是一个知名的电影信息平台&#xff0c;提供了丰富的电影相关数据。通过这个练习&#xff0c;您将深入学习如何抓取动…...