Android开发中,服务端签名后上传文件到阿里云OSS

官方文档:https://help.aliyun.com/document_detail/31920.html
可能我太菜了,官方文档写的很多东西感觉不全,或者不好找,按照下面这些步骤,可能更好理解并实践成功。

一.开通子用户

oss管理控制台

二.设置各种权限

文档:使用STS临时访问凭证访问OSS
开通子用户以后,这个文档了解STS临时访问原理
进入RAM控制台

1.创建RAM用户


访问密钥一定要保存好,只有创建的时候能看到

2.为RAM用户添加STS服务权限

  1. 单击已创建RAM用户右侧对应的添加权限
  2. 添加权限页面,选择AliyunSTSAssumeRoleAccess权限。

3. 创建用于获取临时访问凭证的角色(用于给RAM用户授权)


角色名自己起,最好有特定含义。保存 ARN

4.为角色授权上传文件的权限

创建上传文件的自定义权限策略

  1. 在左侧导航栏的权限管理菜单下,单击权限策略管理。
  2. 单击创建权限策略
  3. 在新建自定义权限策略页面,填写策略名称为RamTestPolicy[最好与角色名称保存相关,这样意义更明确],配置模式选择脚本配置,并在策略内容中赋予角色向目标存储空间examplebucket这个是你自己要上传的bucket】下的目录exampledir这是是你允许这个角色上传数据能保存的文件夹】上传文件的权限。
{"Version": "1","Statement": [{"Effect": "Allow","Action": ["oss:PutObject"],"Resource": ["acs:oss:*:*:examplebucket/exampledir","acs:oss:*:*:examplebucket/exampledir/*"]}]
}
  1. 点击确定

创建完自定义权限,给角色授予这个自定义的权限

  1. 在左侧导航栏的身份管理菜单下,单击角色
  2. 角色页面,找到目标RAM角色RamOssTest【你刚创建的角色名】。
  3. 单击RAM角色RamOssTest右侧的添加权限
  4. 添加权限页面下的自定义策略页签,选择已创建的自定义权限策略RamTestPolicy。
  5. 单击确定

注意: 上面这个自定义的策略,只允许了角色 上传文件、其只能上传到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 {@AutowiredOSS 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));}}

还有异步上传可以看阿里云文档-简单上传

本文链接:https://my.lmcjl.com/post/2335.html

展开阅读全文

4 评论

留下您的评论.