zoukankan      html  css  js  c++  java
  • 阿里云对象存储 OSS 应用服务器搭建代码

    背景说明

    最近做一个APP客户端图片直传阿里云OSS的服务,需要在后台开一个阿里云的OSSToken获取的接口。

    阿里云官方文档地址:快速搭建移动应用直传服务

    略过移动端说明,直接看服务端的。

    不是移动端直传吗,为什么需要服务端呢?原因如下:

    Android和iOS应用不能直接存储AccessKey,这样会存在数据泄露的风险。所以应用必须向用户的应用服务器申请一个Token。

    这个Token是有时效性的,如果Token的过期时间是30分钟(由应用服务器指定),那么在这30分钟里,该Android/iOS应用可以使用此Token从OSS上传和下载数据, 30分钟后需要重新获取Token。

    正确返回的参数 Expiration 为该Token失效的时间。Android SDK会自动判断Token是否失效,如果失效,则自动获取Token。

    代码实现

    这里有个Java代码示例,可以下载来参考,把功能集成到项目中,没必要为一个接口单独部署一个项目到服务器。

    项目环境是 SpringBoot2.0,JDK8(虽然官方说的是适用java1.7,但是JDK8兼容可用。)

    添加依赖

    首先在pom中添加相关依赖

            <!--阿里云对象存储-->
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>aliyun-java-sdk-core</artifactId>
                <version>3.5.1</version>
            </dependency>
            <dependency>
                <groupId>com.aliyun</groupId>
                <artifactId>aliyun-java-sdk-sts</artifactId>
                <version>3.0.0</version>
            </dependency>
            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>3.0.0</version>
            </dependency>    

    配置属性文件

    可以从下载的 AppTokenServerDemo 项目中找到 config.json 文件,将其中的五个参数都配置到我们自己的属性文件 application.properties 中。

    #阿里云对象存储
    ali.oss.AccessKeyID=xxxxxx
    ali.oss.AccessKeySecret=xxxxxxxxxxxxxxx
    ali.oss.RoleArn=xxxxxxxxxxxxxx
    ali.oss.TokenExpireTime=900
    ali.oss.PolicyFile=policy/all_policy.txt

    编写接口类

    import com.alibaba.fastjson.JSONObject;
    import com.aliyuncs.DefaultAcsClient;
    import com.aliyuncs.exceptions.ClientException;
    import com.aliyuncs.http.MethodType;
    import com.aliyuncs.http.ProtocolType;
    import com.aliyuncs.profile.DefaultProfile;
    import com.aliyuncs.profile.IClientProfile;
    import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
    import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.web.bind.annotation.*;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.*;
    
    /**
     * @date 2019/4/7 20:18
     * @auther wangbo
     */
    @Api(tags = {"OSS接口类"})
    @RestController
    @RequestMapping("/api/oss")
    public class ALiOSSController {
        //只有 RAM用户(子账号)才能调用 AssumeRole 接口
        //阿里云主账号的AccessKeys不能用于发起AssumeRole请求
        //请首先在RAM控制台创建一个RAM用户,并为这个用户创建AccessKeys
        @Value("${ali.oss.AccessKeyID}")
        private String accessKeyId;
    
        @Value("${ali.oss.AccessKeySecret}")
        private String accessKeySecret;
    
        //RoleArn 需要在 RAM 控制台上获取
        @Value("${ali.oss.RoleArn}")
        private String roleArn;
    
        //Token 过期时间,默认 900s
        @Value("${ali.oss.TokenExpireTime}")
        private Long tokenExpireTime;
    
        //阿里云对象存储例子的 token 权限文件
        //all_policy.txt:指定了该token拥有对该账号下创建Bucket、删除Bucket、上传文件、下载文件、删除文件的权限 。
        //bucket_read_policy.txt:指定了该token拥有该账号下对指定Bucket的读权限。
        //bucket_read_write_policy.txt:指定了该token拥有该账号下对指定Bucket的读写权限。
        @Value("${ali.oss.PolicyFile}")
        private String policyFile;
    
        //目前只有"cn-hangzhou"这个region可用, 不要使用填写其他region的值
        private static final String REGION_CN_HANGZHOU = "cn-hangzhou";
    
        //这个是STS版本值
        private static final String STS_API_VERSION = "2015-04-01";
    
        @ApiOperation(value = "获取APPToken", notes = "获取阿里云对象存储的token")
        @GetMapping("/getAppToken")
        public void getAppToken(HttpServletRequest request, HttpServletResponse response) throws IOException {
            //RoleSessionName 是临时Token的会话名称,自己指定用于标识你的用户,主要用于审计,或者用于区分Token颁发给谁
            //但是注意RoleSessionName的长度和规则,不要有空格,只能有'-' '_' 字母和数字等字符
            //具体规则请参考API文档中的格式要求
            String roleSessionName = "alice-001";
            //此处必须为 HTTPS
            ProtocolType protocolType = ProtocolType.HTTPS;
            //获取文件的字符串
            String policy = ReadJson(policyFile);
            //创建json对象
            JSONObject respMap = new JSONObject();
            try {
                final AssumeRoleResponse stsResponse = assumeRole(accessKeyId, accessKeySecret, roleArn, roleSessionName,
                        policy, protocolType, tokenExpireTime);
                //设置获取阿里云对象存储成功的值
                respMap.put("StatusCode", "200");
                respMap.put("AccessKeyId", stsResponse.getCredentials().getAccessKeyId());
                respMap.put("AccessKeySecret", stsResponse.getCredentials().getAccessKeySecret());
                respMap.put("SecurityToken", stsResponse.getCredentials().getSecurityToken());
                respMap.put("Expiration", stsResponse.getCredentials().getExpiration());
            } catch (ClientException e) {
                //设置获取阿里云对象存储失败的值
                respMap.put("StatusCode", "500");
                respMap.put("ErrorCode", e.getErrCode());
                respMap.put("ErrorMessage", e.getErrMsg());
            }
            //response写回json数据
            response(request, response,respMap.toJSONString());
        }
    
        protected AssumeRoleResponse assumeRole(String accessKeyId, String accessKeySecret, String roleArn,
                                                        String roleSessionName, String policy, ProtocolType protocolType, long durationSeconds) throws ClientException{
            try {
                //创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
                IClientProfile profile = DefaultProfile.getProfile(REGION_CN_HANGZHOU, accessKeyId, accessKeySecret);
                DefaultAcsClient client = new DefaultAcsClient(profile);
    
                //创建一个 AssumeRoleRequest 并设置请求参数
                final AssumeRoleRequest request = new AssumeRoleRequest();
                request.setVersion(STS_API_VERSION);
                request.setMethod(MethodType.POST);
                request.setProtocol(protocolType);
    
                request.setRoleArn(roleArn);
                request.setRoleSessionName(roleSessionName);
                request.setPolicy(policy);
                request.setDurationSeconds(durationSeconds);
    
                //发起请求,并得到response
                final AssumeRoleResponse response = client.getAcsResponse(request);
    
                return response;
            }catch (ClientException e){
                throw e;
            }
        }
    
        /**
         * 读取配置文件
         * @param path
         * @return
         */
        public static String ReadJson(String path){
            BufferedReader reader = null;
            //返回值,使用StringBuffer
            StringBuffer data = new StringBuffer();
            try {
                //从给定位置获取文件
                ClassPathResource resource = new ClassPathResource(path);
                InputStream inputStream = resource.getInputStream();
                reader = new BufferedReader(new InputStreamReader(inputStream));
                //每次读取文件的缓存
                String temp = null;
                while((temp = reader.readLine()) != null){
                    data.append(temp);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                //关闭文件流
                if (reader != null){
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return data.toString();
        }
    
        /**
         * 服务器响应结果
         * @param request
         * @param response
         * @param results
         * @throws IOException
         */
        private void response(HttpServletRequest request, HttpServletResponse response, String results) throws IOException {
            String callbackFunName = request.getParameter("callback");
            if (callbackFunName==null || callbackFunName.equalsIgnoreCase(""))
                response.getWriter().println(results);
            else
                response.getWriter().println(callbackFunName + "( "+results+" )");
            response.setStatus(HttpServletResponse.SC_OK);
            response.flushBuffer();
        }
    }

    此外需要把相关的资源文件(可以在下载的demo项目中获取)引入到resource目录下:

    踩坑记录

    代码中的文件读取部分在我本地 idea 中运行服务时,可以正常执行。但是将服务打包成可执行jar的包,以jar服务运行服务时报错。

    java.io.FileNotFoundException: class path resource [policay/all_policay.txt] cannot be resolved to absolute file path because it does not reside in the file system

    原因:打包后Spring无法使用resource.getFile()访问JAR中的路径的文件,必须使用resource.getInputStream()。

    我尝试了好几种:

    (1)使用demo项目中的方式,本地线上都找不到文件

    File file = new File("policay/all_policay.txt");
    BufferedReader reader = new BufferedReader(new FileReader(file));

    (2)使用ResouceUtils类,线上版本找不到文件

    File file = ResourceUtils.getFile("classpath:policay/all_policay.txt");
    BufferedReader reader = new BufferedReader(new FileReader(file));

    (3)最后改为使用InputStream才解决问题。

    ClassPathResource resource = new ClassPathResource("policay/all_policay.txt");
    InputStream inputStream
    = resource.getInputStream();
    BufferedReader reader
    = new BufferedReader(new InputStreamReader(inputStream));

    另外注意,该接口需要定义为GET接口,并且响应值不能自定义的,需要按照demo中的形式进行响应,因为该接口是给阿里云OSS调用的,前端会在相应位置配置该接口地址。

    参考博客:

    快速上手阿里云对象存储(一)

    快速上手阿里云对象存储(二)

    快速上手阿里云对象存储(三)

  • 相关阅读:
    Android 异步请求通用类
    Android 异步下载
    Eclipse 使用 VS Emulator for android 调试环境配置 步骤
    android ListView 可缩放,支持左右上下手势
    安卓中自定义控件引用
    java中的可释放资源定义,类似c#中的using
    java 实现自定义事件
    c# android 全局捕获未处理异常
    java android 捕获未处理异常
    java 中异常处理示例并捕获完整异常内容
  • 原文地址:https://www.cnblogs.com/wbxk/p/10669659.html
Copyright © 2011-2022 走看看