平时在开发中有这样一种场景,一个账号动态创建桶并生成对象;另外一个只读账号,只有获取对象的权限。这个时候,AmazonS3 需要每创建一个桶,就要给只读账号授权一次。如果桶是经常创建的,通过管理界面控制台,都这样授权,不是很方便,也容易忘记做授权。这个时候,我们可以通过sdk,在创建桶和上传对象的时候,给相应的只读账号授权,让其具有读对象的权限。
读写账号:user-rw
只读账号:user-read
1.用读写账号的创建桶的时候,授权只读账号能读取桶的权限
// 创建桶
public Bucket creatingBucket(String bucketName)
{
Bucket bucket = null;
try {
bucket = xskyS3Base.getAmazonS3().createBucket(bucketName);
}catch (AmazonServiceException ase) {
log.error("Caught an AmazonServiceException when create buket:{} Error Message:{},HTTP Status Code:{}," +
"AWS Error Code:{},Error Type:{},Request ID:{}",bucketName,
ase.getMessage(),ase.getStatusCode(),ase.getErrorCode(),ase.getErrorType(),ase.getRequestId());
throw new RRException("creatingBucket "+bucketName+" fail");
}
grantsBucketAcl(bucketName);
return bucket;
}
public void grantsBucketAcl(String bucketName){
try {
String readUser = "user-read"
if(StringUtils.isNotBlank(readUser)){
AccessControlList acl = xskyS3Base.getAmazonS3().getBucketAcl(bucketName); //获取桶的权限信息
if(acl!=null){
Grantee grantee = new CanonicalGrantee(readUser);
acl.grantPermission(grantee,Permission.Read);//授权可读
xskyS3Base.getAmazonS3().setBucketAcl(bucketName,acl);
log.info("桶用户:{}授权成功",readUser);
}else{
log.error("通过桶:{}查询不到acl信息",bucketName);
}
}
} catch (SdkClientException e) {
log.error("授权失败",e);
}
}
- 初始化amazons3
import com.amazonaws.AmazonClientException;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.Protocol;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.chain.common.config.KsKyConifg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@Component
@Slf4j
public class XskyS3Base {
@Autowired
private KsKyConifg ksKyConifg;
private AmazonS3 client = null;
@PostConstruct
private void init(){
client = intXskyS3Basic(ksKyConifg.getServiceUrl(),ksKyConifg.getKeyId(),ksKyConifg.getKeySecret());
}
public AmazonS3 getAmazonS3(){
return client;
}
//创建连接
private AmazonS3 intXskyS3Basic(String serverUrl, String access_key, String secret_key) {
AWSCredentials credentials = null;
try {
credentials = new BasicAWSCredentials(access_key, secret_key);
} catch (Exception e) {
log.error("Authentication failed access_key:{},secret_key:{}",access_key,secret_key,e);
throw new AmazonClientException(
"Authentication failed access_key:"+access_key+",secret_key:"+secret_key, e);
}
//初始化S3 configure 的实例
ClientConfiguration config = new ClientConfiguration();
config.setProtocol(Protocol.HTTP);
config.setUseExpectContinue(false);
config.setMaxConnections(ksKyConifg.getClientMaxConnections()); // 最大连接数 200
config.setConnectionTimeout(ksKyConifg.getClientConnectionTimeout());//10000
config.setSocketTimeout(ksKyConifg.getClientSocketTimeout());//30000
config.setConnectionTTL(ksKyConifg.getClientConnectionTTL()); // CPoolEntry 最大有效值.2 * 60 * 1000
config.setConnectionMaxIdleMillis(ksKyConifg.getClientConnectionMaxIdleMillis()); // 客户端能接受的最大 Keep-Alive 值 60 * 1000
config.withUseExpectContinue(false);
config.withSignerOverride("S3SignerType");
AwsClientBuilder.EndpointConfiguration end_point = new AwsClientBuilder.EndpointConfiguration(serverUrl, "us-east-1");
//创建连接,替换原AmazonS3Client接口
client = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withClientConfiguration(config)
.withEndpointConfiguration(end_point)
.withPathStyleAccessEnabled(true)
.build();
return client;
}
}
3.上传对象并授予权限
public PutObjectResult putObject(String bucketName, String key, File file)
{
PutObjectResult putResult = null;
try {
ObjectMetadata metadata = new ObjectMetadata();
PutObjectRequest putRequest = new PutObjectRequest(bucketName, key, file);
//设置认证只读,这种授权需要有账号的方式才能读取
putRequest.setCannedAcl(CannedAccessControlList.AuthenticatedRead);
//还有种CannedAccessControlList.PublicRead,这个打开,会再浏览器地址能直接打开下载录音
putResult = xskyS3Base.getAmazonS3().putObject(putRequest);
}catch(AmazonServiceException ase) {
log.error("Caught an AmazonServiceException when put object of:{} Error Message:{},HTTP Status Code:{}," +
"AWS Error Code:{},Error Type:{},Request ID:{} error:{}",key,
ase.getMessage(),ase.getStatusCode(),ase.getErrorCode(),ase.getErrorType(),ase.getRequestId(),ase.getErrorMessage(),ase);
throw new RRException("putObject to bucket:"+bucketName+",key:"+key+" fail");
}
return putResult;
}
另外一种方式,也在给每个对象设置权限;这种方式需要对象上传后,再设置。这种方式的缺点就是,单独授权的时候,需要另外再发起一次网络请求授权
//对每个对象进行授权
public void grantsObject(String bucketName,String key){
try {
String readUser = "user-read";
if(StringUtils.isNotBlank(readUser)&&StringUtils.isNotBlank(bucketName)&&StringUtils.isNotBlank(key)){
AccessControlList acl = xskyS3Base.getAmazonS3().getObjectAcl(bucketName,key);
if(acl!=null){
Grantee grantee = new CanonicalGrantee(readUser);
acl.grantPermission(grantee,Permission.Read);
xskyS3Base.getAmazonS3().setObjectAcl(bucketName,key,acl);
log.info("授权对象的只读账号");
}else{
log.error("根据桶:{}和key:{}查询不到对象的acl信息无法对只读账号授权对象权限失败",bucketName,key);
}
}
} catch (SdkClientException e) {
log.error("只读账号授权对象权限失败,桶:{}和key:{}",bucketName,key,e);
}
}
其他授权通知
1.EmailAddressGrantee,可以将对象发送到某个邮件地址
- GroupGrantee 组授权
直接生成公共的url地址
xskyS3Base.getAmazonS3().setObjectAcl(bucketName, key,CannedAccessControlList.PublicRead);
//获取一个request
GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(bucketName, key);
//生成公用的url
URL url = xskyS3Base.getAmazonS3().generatePresignedUrl(urlRequest);
生成过期时间的对象
GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(bucketName, key);
java.util.Date expiration = new java.util.Date();
long milliSeconds = expiration.getTime();
milliSeconds += 1000 * 60 * 60; // Add 1 hour.
expiration.setTime(milliSeconds);
urlRequest.setExpiration(expiration); //设置过期时间
URL url = xskyS3Base.getAmazonS3().generatePresignedUrl(urlRequest);
UploadObject(url);
public static void UploadObject(URL url) throws IOException
{
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
OutputStreamWriter out = new OutputStreamWriter(
connection.getOutputStream());
out.write("This text uploaded as object.");
out.close();
int responseCode = connection.getResponseCode();
System.out.println("Service returned response code " + responseCode);
}
参考:
https://zhuanlan.zhihu.com/p/194272308
https://blog.csdn.net/hellozhxy/article/details/84070837
https://blog.csdn.net/anhuidelinger/article/details/9831861