1、背景
在上一篇中:Docker部署Minio并与Springboot的集成_木星mx的博客-CSDN博客
我们介绍了如何部署minio和与springboot的集成方法,但是在上传文件时,采用的是从浏览器获取参数读取本地文件上传,当项目部署到线上时,用户和项目服务处于不同机器上,这种方式就不适用了,因此需要进行升级。
升级后的效果是:项目服务只提供签名服务,用户通过访问项目提供的接口获取签名,然后用户使用签名上传文件,实现了用户到oss端对端的文件传输
2、实践
1、工具准备
(1)sts配置工具aws
minio本身具备sts签名服务,但需要借助第三方工具配置,我们选择aws
因此必须先安装aws应用:
//下载安装包
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.0.30.zip" -o "awscliv2.zip"
//解压文件
unzip awscliv2.zip
//安装,root用户sudo可以去掉
sudo ./aws/install
(2)minio客户端mc
aws提供的授权服务必须绑定到minio服务上,因此需要一个minio客户端,它可以以命令
的方式操作minio服务
//在当前目录下载mc
wget https://dl.min.io/client/mc/release/linux-amd64/mc
//设置为可执行
chmod +x mc
//在本目录执行mc命令,查看mc提供的操作命令
./mc --help
2、为minio(oss)服务绑定sts授权服务
1、给mc绑定minio服务
要让mc控制minio服务,首先得为mc配置minio服务的地址,需要提供:
minio的ip和端口号,minio的用户名和密码,local表示配置本地服务
./mc config host add local http://127.0.0.1:9000 username password
配置完成之后可以在~/.mc/config.json中查看,local配置好了本地的minio服务
2、使用mc命令为刚刚配置的minio服务绑定访问策略
(1)首先需要创建一个json文件,名字可以随便起,键入以下内容
Version是版本号,Action里是允许使用s3接口的删除、获取上传对象功能
Resource是访问控制,*表示可以访问minio服务的所有bucket,若想限制访问
名为test的bucket可替换成"arn:aws:s3:::test/*" ,表示只可访问名为test的bucket
限制访问这一块我们可以在具体编码时实现
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:DeleteObject",
"s3:GetObject",
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::*"
]
}
]
}
(2)接着就是将json文件中的访问策略正式绑定到minio服务上了
//表示为local的minio服务绑定一个叫minio的访问策略,后面是策略文件的地址
./mc admin policy add local minio /home/mxShop/minio/config/company.json
查看绑定的策略:./mc admin policy info local minio
若出现:-bash: ./mc: No such file or directory,需要切换到mc所在目录
3、创建用户并为该用户绑定策略
策略需要绑定搭配minio用户上,可新建一个,也可使用安装minio服务时的那个
(1)创建用户
//为local的minio服务创建一个minio用户,密码为miniopwd
./mc admin user add local minio miniopwd
(2)绑定策略
//将前面的minio策略绑定给minio用户
./mc admin policy set local minio user=minio
4、使用aws进行sts配置
为minio服务绑定完策略后,需要使用aws配置该策略
aws configure --profile minio
执行完上面命令后需要进行配置:
一、二行是minio用户的信息,三行是aws服务的站点,这里表示中国北京
第四行是文件类型
AWS Access Key ID [None]: minio
AWS Secret Access Key [None]: miniopwd
Default region name [None]: cn-north-1
Default output format [None]: json
配置完的信息可在~/.aws目录下进行查看和修改
3、测试
输入以下命令
--profile:指定策略
--prolicy:进行二次策略限制,格式与之前的策略相同
aws --profile minio \
--endpoint-url 'http://localhost:9000' \
sts assume-role \
--policy '{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Action": ["s3:GetObject"],"Resource": ["arn:aws:s3:::*"]}]}' --role-arn 'arn:aws:s3:::*' \
--role-session-name anything
结果:这些就是我们需要的签名信息了
{
"Credentials": {
"AccessKeyId": "JJOUBSPDSK20Y2500847",
"SecretAccessKey": "QpXMeXQHE+qYGddh5On+DlWYXpenK+j5yOHBn4Hm",
"SessionToken": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJKSk9VQlNQRFNLMjBZMjUwMDg0NyIsImV4cCI6MTY0MTg5NTQxNiwicGFyZW50IjoibWluaW8iLCJzZXNzaW9uUG9saWN5IjoiZXlKV1pYSnphVzl1SWpvZ0lqSXdNVEl0TVRBdE1UY2lMQ0pUZEdGMFpXMWxiblFpT2lCYmV5SkZabVpsWTNRaU9pQWlRV3hzYjNjaUxDSkJZM1JwYjI0aU9pQmJJbk16T2tkbGRFOWlhbVZqZENKZExDSlNaWE52ZFhKalpTSTZJRnNpWVhKdU9tRjNjenB6TXpvNk9pb2lYWDFkZlE9PSJ9.Gt2I3TG0jpvApAQrrS1QEZV0N3cIbtXnbNQ07-qe2cLb-uty-IaiVYhCyUHG80vwqJCxjnHiqYitziMWZna6sg",
"Expiration": "2022-01-11T10:03:36+00:00"
},
"AssumedRoleUser": {
"Arn": ""
}
}
4、java代码测试使用签名上传
需要注意的是,这里的二次策略限制,范围必须在之前配置的策略范围内,超出绑定策略范围会报错,这里是限制了只能访问名为bucket的桶,若将BUCKET的值改为其他桶的名称会被拒绝(报错)
public class Test03 {
//服务所在ip地址和端口
public static final String ENDPOINT = "http://192.17.54.1:9000/";
//mc的用户名
public static final String ACCESS_KEY_COMPANY = "minio";
//mc的密码
public static final String SECRET_KEY_COMPANY = "miniopwd";
//aws服务端点
public static final String REGION = "cn-north-1";
//上传的bucket名
public static final String BUCKET = "bucket";
//授权策略,允许访问名为bucket的桶的目录
public static final String ROLE_ARN = "arn:aws:s3:::bucket/*";
public static final String ROLE_SESSION_NAME = "anysession";
//定义策略,可进行二次限定
public static final String POLICY_GET_AND_PUT = "{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Action\": [\n" +
" \"s3:GetObject\",\n" +
" \"s3:PutObject\"\n" +
" ],\n" +
" \"Resource\": [\n" +
" \"arn:aws:s3:::bucket/*\"\n" +
" ]\n" +
" }\n" +
" ]\n" +
"}";
public static void main(String[] args) {
try {
//创建签名对象
AssumeRoleProvider provider = new AssumeRoleProvider(
ENDPOINT,
ACCESS_KEY_COMPANY,
SECRET_KEY_COMPANY,
3600,//默认3600秒失效,设置小于这个就是3600,大于3600就实际值
POLICY_GET_AND_PUT,
REGION,
ROLE_ARN,
ROLE_SESSION_NAME,
null,
null);
/**
* 打印provider签名属性
*/
System.out.println(provider.fetch().sessionToken());
System.out.println(provider.fetch().accessKey());
System.out.println(provider.fetch().secretKey());
System.out.println(provider.fetch().isExpired());
//使用签名获取mc对象
MinioClient minioClient = MinioClient.builder()
.endpoint(ENDPOINT)
.credentialsProvider(provider)
.build();
String filename = "任务(1).docx";
try {
//对象流,获取文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\" + filename));
//使用mc对象上传文件
minioClient.putObject(PutObjectArgs.builder()
//桶名和aws服务端点
.bucket(BUCKET).region(REGION)
//前缀和对象名
.object("mx/" + filename)
.stream(bis, bis.available(), -1)
.build());
System.out.println("文件上传成功!!");
} catch (ErrorResponseException e) {
e.printStackTrace();
} catch (InsufficientDataException e) {
e.printStackTrace();
} catch (InternalException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidResponseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ServerException e) {
e.printStackTrace();
} catch (XmlParserException e) {
e.printStackTrace();
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}