官方文档:https://help.aliyun.com/document_detail/31920.html
可能我太菜了,官方文档写的很多东西感觉不全,或者不好找,按照下面这些步骤,可能更好理解并实践成功。
一.开通子用户
二.设置各种权限
文档:使用STS临时访问凭证访问OSS
开通子用户以后,这个文档了解STS临时访问原理
进入RAM控制台
1.创建RAM用户
访问密钥一定要保存好,只有创建的时候能看到
2.为RAM用户添加STS服务权限
- 单击已创建RAM用户右侧对应的添加权限。
- 在添加权限页面,选择AliyunSTSAssumeRoleAccess权限。
3. 创建用于获取临时访问凭证的角色(用于给RAM用户授权)
角色名自己起,最好有特定含义。保存 ARN
4.为角色授权上传文件的权限
创建上传文件的自定义权限策略
- 在左侧导航栏的权限管理菜单下,单击权限策略管理。
- 单击创建权限策略
- 在新建自定义权限策略页面,填写策略名称为RamTestPolicy[最好与角色名称保存相关,这样意义更明确],配置模式选择脚本配置,并在策略内容中赋予角色向目标存储空间examplebucket【这个是你自己要上传的bucket】下的目录exampledir【这是是你允许这个角色上传数据能保存的文件夹】上传文件的权限。
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"oss:PutObject"
],
"Resource": [
"acs:oss:*:*:examplebucket/exampledir",
"acs:oss:*:*:examplebucket/exampledir/*"
]
}
]
}
- 点击确定
创建完自定义权限,给角色授予这个自定义的权限
- 在左侧导航栏的身份管理菜单下,单击角色。
- 在角色页面,找到目标RAM角色RamOssTest【你刚创建的角色名】。
- 单击RAM角色RamOssTest右侧的添加权限。
- 在添加权限页面下的自定义策略页签,选择已创建的自定义权限策略RamTestPolicy。
- 单击确定。
注意: 上面这个自定义的策略,只允许了角色 上传文件、其只能上传到examplebucket这个bucket中的exampledir这个文件夹中,后续如果上地址不是这个文件夹就会报权限错误:You have no right to access this object because of bucket acl
也可以配置其他更多的、更精细的权限,文档:RAM Policy常见示例
三、获取临时访问凭证,服务器端接口开发
文档中有他们自己编的比较原生的各种语言的服务端接口,
因为同时做web开发,所有自己写了一个接口,开发框架用了spring boot【其实和SSM一样,只不过配置更简单】
接口代码根据官方文档改的。
服务端接口代码:
@RestController //就是普通的Controller 再加 将响应体以json格式返回 即@ResponseBody
public class OssController {
@Autowired
OSS ossClient;
//配置文件中取出accessId、sts_endpoint、accessKeySecret、roleArn这些值
@Value("${spring.cloud.alicloud.access-key}")
private String accessId;
@Value("${sts_endpoint}")
private String sts_endpoint;
@Value("${roleArn}")
private String roleArn;
@Value("${roleSessionName}")
private String roleSessionName;
@Value("${spring.cloud.alicloud.secret-key:}")
private String accessKeySecret;
/**
* 获取临时访问凭证
* @return
*/
@RequestMapping("/oss/sts")
public R sts(){
// 自定义角色会话名称,用来区分不同的令牌,例如可填写为SessionTest。
String roleSessionName = "SessionTest";
String policy = "{\n" +
" \"Version\": \"1\", \n" +
" \"Statement\": [\n" +
" {\n" +
" \"Action\": [\n" +
" \"oss:PutObject\"\n" +
" ], \n" +
" \"Resource\": [\n" +
" \"acs:oss:*:*:sleep-monitor/*\" \n" +
" ], \n" +
" \"Effect\": \"Allow\"\n" +
" }\n" +
" ]\n" +
"}";
Map<String, Object> respMap = null;
try {
// regionId表示RAM的地域ID。以华东1(杭州)地域为例,regionID填写为cn-hangzhou。也可以保留默认值,默认值为空字符串("")。
String regionId = "cn-beijing";
// 添加endpoint。
DefaultProfile.addEndpoint(regionId, "Sts", sts_endpoint);
// 构造default profile。
IClientProfile profile = DefaultProfile.getProfile(regionId, accessId, accessKeySecret);
// 构造client。
DefaultAcsClient client = new DefaultAcsClient(profile);
final AssumeRoleRequest request = new AssumeRoleRequest();
request.setSysMethod(MethodType.POST);
request.setRoleArn(roleArn);
request.setRoleSessionName(roleSessionName);
request.setPolicy(policy); // 如果policy为空,则用户将获得该角色下所有权限。
request.setDurationSeconds(3600L); // 设置临时访问凭证的有效时间为3600秒。
final AssumeRoleResponse response = client.getAcsResponse(request);
respMap = new HashMap<>();
System.out.println("Expiration: " + response.getCredentials().getExpiration());
System.out.println("Access Key Id: " + response.getCredentials().getAccessKeyId());
System.out.println("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
System.out.println("Security Token: " + response.getCredentials().getSecurityToken());
System.out.println("RequestId: " + response.getRequestId());
respMap.put("Expiration",response.getCredentials().getExpiration());
respMap.put("AccessKeyId",response.getCredentials().getAccessKeyId());
respMap.put("AccessKeySecret",response.getCredentials().getAccessKeySecret());
respMap.put("SecurityToken",response.getCredentials().getSecurityToken());
respMap.put("RequestId",response.getCredentials().getAccessKeyId());
respMap.put("StatusCode",200);
return R.ok(respMap);
} catch (ClientException e) {
System.out.println("Failed:");
System.out.println("Error code: " + e.getErrCode());
System.out.println("Error message: " + e.getErrMsg());
System.out.println("RequestId: " + e.getRequestId());
return R.error().put("data",e);
}
}
}
不管以那种方式写服务端,要求是能正确返回如下的json数据,
包括StatusCode、AccessKeyId、AccessKeySecret、SecurityToken、Expiration
{
"StatusCode":200,
"AccessKeyId":"STS.3p***dgagdasdg",
"AccessKeySecret":"rpnwO9***tGdrddgsR2YrTtI",
"SecurityToken":"CAES+wMIARKAAZhjH0EUOIhJMQBMjRywXq7MQ/cjLYg80Aho1ek0Jm63XMhr9Oc5s˙∂˙∂3qaPer8p1YaX1NTDiCFZWFkvlHf1pQhuxfKBc+mRR9KAbHUefqH+rdjZqjTF7p2m1wJXP8S6k+G2MpHrUe6TYBkJ43GhhTVFMuM3BZajY3VjZWOXBIODRIR1FKZjIiEjMzMzE0MjY0NzM5MTE4NjkxMSoLY2xpZGSSDgSDGAGESGTETqOio6c2RrLWRlbW8vKgoUYWNzOm9zczoqOio6c2RrLWRlbW9KEDExNDg5MzAxMDcyNDY4MThSBTI2ODQyWg9Bc3N1bWVkUm9sZVVzZXJgAGoSMzMzMTQyNjQ3MzkxMTg2OTExcglzZGstZGVtbzI=",
"Expiration":"2017-12-12T07:49:09Z"
}
运行服务端,并测试,访问你的服务地址,看是否能正确的返回json数据
四、安卓手机上传文件到阿里云OSS
首先需要引入oss依赖:文档
- 可以直接在Android Studio环境中添加:
implementation 'com.aliyun.dpa:oss-android-sdk:2.9.10'
- 也可以引入jar包
将aliyun-oss-sdk-android-2.9.5.jar、okhttp-3.x.x.jar、okio-1.x.x.jar 3个jar包导入libs目录。
jar包百度网盘下载:
链接:https://pan.baidu.com/s/1Odc6kDM2_6rlbjo3s_aepA
提取码:lyg6
【我在build.gradle文件中直接添加依赖的时候,出现了依赖个okhttp jar包冲突, 所以选择了第二种方式】
然后直接上代码:
private void uploadFileTest() {
if (HttpUtil.isNetworkAvailable(requireActivity())) {//判断是否有网络
String endpoint = "oss-cn-beijing.aliyuncs.com";
String buckName = "sleep-monitor";
String stsServer = RequestCallback.baseAddress + "api/thirdparty/oss/sts";//请求sts的地址
// 推荐使用OSSAuthCredentialsProvider。token过期可以及时更新。
OSSCredentialProvider credentialProvider = new OSSAuthCredentialsProvider(stsServer);
// //配置类如果不设置,会有默认配置。
// ClientConfiguration conf = new ClientConfiguration();
// conf.setConnectionTimeout(15 * 1000); // 连接超时,默认15秒。
// conf.setSocketTimeout(15 * 1000); // socket超时,默认15秒。
// conf.setMaxConcurrentRequest(5); // 最大并发请求数,默认5个。
// conf.setMaxErrorRetry(2); // 失败后最大重试次数,默认2次。
OSS oss = new OSSClient(MyApplication.getAppContext(), endpoint, credentialProvider);
File[] files = MyApplication.getAppContext().getExternalFilesDirs(null);//获取该应用文件下的内部存储位置
File file = new File(files[0],"20211013脑电丢包测试20211013191115.csv");//要上传的文件
//第二个变量是上传的文件夹,这个文件夹必须是之前自定义权限中写的那个文件夹
PutObjectRequest put = new PutObjectRequest(buckName, "睡眠APP/APP测试.txt", String.valueOf(file));
try {
Log.d(TAG,"开始上传...");
PutObjectResult putResult = oss.putObject(put);
Log.d(TAG,"PutObject: UploadSuccess");
Log.d(TAG,"ETag:" + putResult.getETag());
Log.d(TAG,"RequestId:" + putResult.getRequestId());
} catch (ClientException e) {
// 客户端异常,例如网络异常等。
Log.e(TAG,"客户端异常:" + e);
e.printStackTrace();
} catch (ServiceException e) {
// 服务端异常。
Log.e(TAG,"RequestId:" + e.getRequestId());
Log.e(TAG,"ErrorCode:"+ e.getErrorCode());
Log.e(TAG,"HostId:"+ e.getHostId());
Log.e(TAG,"RawMessage:"+ e.getRawMessage());
}
} else {
ToastUtil.showShortToast(MyApplication.getAppContext().getResources().getString(R.string.network_enable));
}
}
还有异步上传可以看阿里云文档-简单上传