Alibaba Cloud OSS uses RAM to generate STS fragments to upload large files Demo

Alibaba Cloud ordinary Form form upload video

This is the easiest way to upload, use the background to generate Token, and the front end directly uploads to the OSS server through the Form form

Generate Token code in the background

    /**
     * 生成阿里云上传Token
     * @return
     * @throws UnsupportedEncodingException
     */
    @GetMapping("/token")
    public ResponseEntity<ApiResult> token() throws UnsupportedEncodingException {
    
    
        //上传地址
        String uploadUrl = "http://bucketName.oss-cn-hangzhou.aliyuncs.com/";
        String dir = "";
        OSSClient client = new OSSClient(STSUtil.END_POINT, STSUtil.accessKeyId, STSUtil.accessKeySecret);
        long expireEndTime = System.currentTimeMillis() + STSUtil.expirationTime * 1000;
        Date expiration = new Date(expireEndTime);
        PolicyConditions policyConds = new PolicyConditions();
        policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
        policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
        String postPolicy = client.generatePostPolicy(expiration, policyConds);
        byte[] binaryData = postPolicy.getBytes("utf-8");
        String encodedPolicy = BinaryUtil.toBase64String(binaryData);
        String postSignature = client.calculatePostSignature(postPolicy);
        //OSS文件名
        String key = String.format("%s.mp4", UidUtils.generateObjectId());
        JSONObject jasonCallback = new JSONObject();
        //你的回调URL
        jasonCallback.put("callbackUrl", "http://a.com/endpoint/aliyun/uploadSuccess");
		//阿里云回调返回参数
        jasonCallback.put("callbackBody", "id=" + key + "&filename=${object}&type=video&etag=${etag}&size=${size}&mimeType=${mimeType}");
        jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
        String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
        Map<String, String> res = new HashMap<>();
        res.put("callback", base64CallbackBody);
        res.put("key", key);
        res.put("OSSAccessKeyId", STSUtil.accessKeyId);
        res.put("policy", encodedPolicy);
        res.put("success_action_status", "200");
        res.put("signature", postSignature);
        res.put("dir", dir);
        res.put("uploadUrl", uploadUrl);
        res.put("expire", String.valueOf(expireEndTime / 1000));
        return renderOk(res);
    }
//返回数据
{
    
    
    "code": 0,
    "data": {
    
    
        "OSSAccessKeyId": "LTAI4GHdsbaaaaJhK",
        "uploadUrl": "http://bucketName.oss-cn-hangzhou.aliyuncs.com/",
        "signature": "XdVOT2/HiOals03pQjBaR16Cd9o=",
        "success_action_status": "200",
        "expire": "1616640488",
        "callback": "eyJjYWxsYmFja0JvZmaamdHlwsmV9Jm1pbWVUeXBlPSR7bWltZVR5cGV9In0=",
        "dir": "",
        "key": "6688924142276.mp4",
        "policy": "eyJleHBpcmF0aW9uIjOC42MzBaIiiXV19"
    }
}

Front-end upload via form

<div class="main">
    <input onchange="getToken()"
           accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx" id="file" name="file"
           class="ipt" type="file"/>
</div>

<script>
    function getToken() {
    
    
        var xhr = new XMLHttpRequest();
        xhr.open('POST',  "/token", true);
        var formData = new FormData();
        xhr.onload = function (e) {
    
    
            var res = JSON.parse(this.responseText);
            if (res.code == 0) {
    
    
                uploadFile(res, file);
            }
        };
        xhr.send(formData);
    }
    function uploadFile(data, file) {
    
    
        var xhr = new XMLHttpRequest();
        xhr.open('POST', data.uploadUrl, true);
        var formData, startDate;
        formData = new FormData();
        imgInfoId = data.id;
        formData.append("key",data.key)
        formData.append('policy', data.policy);
        formData.append('OSSAccessKeyId', data.OSSAccessKeyId);
        formData.append('success_action_status',200);
        formData.append('callback',data.callback);
        formData.append('signature',data.signature);
        formData.append('file', file.files[0]);
        var taking;
        xhr.upload.addEventListener("progress", function (evt) {
    
    
            if (evt.lengthComputable) {
    
    
                var nowDate = new Date().getTime();
                taking = nowDate - startDate;
                var x = (evt.loaded) / 1024;
                var y = taking / 1000;
                var uploadSpeed = (x / y);
                var formatSpeed;
                if (uploadSpeed > 1024) {
    
    
                    formatSpeed = (uploadSpeed / 1024).toFixed(2) + "Mb\/s";
                } else {
    
    
                    formatSpeed = uploadSpeed.toFixed(2) + "Kb\/s";
                }
                var percentComplete = Math.round(evt.loaded * 100 / evt.total);
                //计算进度及速度
                console.log(percentComplete, ",", formatSpeed);
            }
        }, false);

        xhr.onreadystatechange = function (response) {
    
    
            if (xhr.readyState == 4 && xhr.status == 200 && xhr.responseText != "") {
    
    
                console.info("success")
            } else if (xhr.status != 200 && xhr.responseText) {
    
    
				console.info("error")
            }
        };
        startDate = new Date().getTime();
        xhr.send(formData);

    }

</script>



insert image description here

method features

This upload method is easy and simple, but the disadvantage is that the upload speed is slow, it does not support large file uploads, and the file size and quantity cannot be used at the G level, and it is easy to cause the browser to freeze, so large files need to be uploaded in pieces

STS multipart upload

Configure RAM

1. RAM creates a user and generates an AK SK. When uploading, use this set of AK/SK to
insert image description here
assign the user the authority to generate STS and control OSS
AliyunSTSAssumeRoleAccess
AliyunOSSFullAccess
insert image description here

2. Create a RAM role and assign it to the ARN

insert image description here

3. Bucket configures OSS cross-domain to add Etag and x-oss-request-id to expose Headers and allow cross-uploading

insert image description here

Backend generates STS Token


    /**
     * 生成STS token
     * @return
     * @throws ClientException
     */
    @GetMapping("/sts")
    public ResponseEntity<ApiResult> sts() throws ClientException {
    
    
        Map<String, Object> response = new HashMap<>();
        Map<String, Object> callback = new HashMap<>();
        callback.put("callbackBodyType", "application/x-www-form-urlencoded");
        callback.put("callbackUrl", "http://a.com/endpoint/aliyun/uploadSuccess");
        callback.put("callbackBody", "id=123123123&filename=${object}&type=video&etag=${etag}&size=${size}&mimeType=${mimeType}");
        AssumeRoleResponse.Credentials credentials = STSUtil.createSTSForPutObject(STSUtil.bucketName, STSUtil.ROLE_ARN, STSUtil.accessKeyId, STSUtil.accessKeySecret, STSUtil.expirationTime);
        Map<String, Object> res = mapOf("credentials", credentials, "fileKey", UidUtils.generateObjectId() + ".mp4", "bucket", STSUtil.bucketName, "region", STSUtil.REGION_CN_HANGZHOU, "endpoint", STSUtil.END_POINT);
        response.put("callback", callback);
        response.putAll(res);
        return renderOk(response);
    }

Front-end multipart upload

<html>
<head>
       
    <script src="https://meizi-tm-5108-pub.oss-cn-hangzhou.aliyuncs.com/lib/aliyun-upload-sdk/lib/aliyun-oss-sdk-6.13.0.min.js"></script>
    <script src="https://meizi-tm-5108-pub.oss-cn-hangzhou.aliyuncs.com/lib/aliyun-upload-sdk/lib/base64.js"></script>

</head>
<body>
  <input type="file" id="file"/>
<span id="process"></span>
<span id="res"></span> 

<script type="text/javascript">
    document.getElementById('file').addEventListener('change', function (e) {
    
    
        var file = e.target.files[0];
        //获取STS
        OSS.urllib.request("/sts",
            {
    
    method: 'GET'},
            function (err, response) {
    
    
                if (err) {
    
    
                    return alert(err);
                }
                try {
    
    
                    result = JSON.parse(response);
                } catch (e) {
    
    
                    return alert('parse sts response info error: ' + e.message);
                }
                //64位编码 
                var parses = function (data) {
    
    
                    var base = new Base64();
                    return base.encode(JSON.stringify(data));
                }
                var client = new OSS({
    
    
                    accessKeyId: result.data.credentials.accessKeyId,
                    accessKeySecret: result.data.credentials.accessKeySecret,
                    stsToken: result.data.credentials.securityToken,
                    endpoint: result.data.endpoint,
                    bucket: result.data.bucket,
                    region: result.data.region,
                });
                client.multipartUpload(result.data.fileKey, file, {
    
    
                    parallel: 4,
                    partSize: 1024 * 1024,
                    mime: 'video/mp4',
                    headers: {
    
    
                        'x-oss-callback': parses(result.data.callback)
                    },
                    progress: function (p, checkpoint) {
    
    
                        document.getElementById('process').innerHTML = p * 100 + "%";
                    }
                }).then(function (result) {
    
    
                    console.log(result);
                    document.getElementById('res').innerHTML = "上传成功:" + JSON.parse(result).data.filename;
                }).catch(function (err) {
    
    
                    console.log(err);
                });
            });
    });

</script>
</body>
</html>

Complete multipart upload

During the transfer process, I encountered many problems related to permissions. Ali’s RAM is indeed a bit complicated, and it is a bit difficult to get started for the first time. However, this set of permission control is really good, and it can precisely control the generated AK/SK to access any resource on the cloud. CRUD permissions, security is guaranteed.
insert image description here

STSUtil.java

package com.zjrb.media.base.util.aliyun;

import com.alibaba.fastjson.JSON;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
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 com.aliyuncs.sts.model.v20150401.AssumeRoleResponse.Credentials;

import java.io.File;

/**
 * @version 1.0
 * @describe: OSS临时访问凭证授权
 * @author:houkai
 * @Date: 2018/3/7 14:54
 */
public class STSUtil {
    
    

    /**
     * 目前只有"cn-hangzhou"这个region可用, 不要使用填写其他region的值
     */
    public static final String REGION_CN_HANGZHOU = "cn-hangzhou";
    /**
     * 当前 STS API 版本
     */
    public static final String STS_API_VERSION = "2015-04-01";
    /**
     * 必须是https请求
     */
    public static final ProtocolType PROTOCOL_TYPE = ProtocolType.HTTPS;
    /**
     * 指定角色的全局资源描述符(Aliyun Resource Name,简称Arn)
     */
    public static final String ROLE_ARN = "acs:ram::1717083:role/media-upload";
    /**
     * 用户自定义参数。此参数用来区分不同的Token,可用于用户级别的访问审计
     */
    public static final String ROLE_SESSION_NAME = "test";
    /**
     * 阿里云EndPoint
     */
    public static final String END_POINT = "http://oss-cn-hangzhou.aliyuncs.com/";
    /**
     * 上传的Bucket
     */
    public static final String bucketName = "bucketName";
    /**
     * RAM里的用户 AK,不可用全局AK
     */
    public static final String accessKeyId = "aa";
    /**
     * RAM里的用户 SK,不可用全局SK
     */
    public static final String accessKeySecret = "aabb";
    /**
     * 生成的ak sk 过期时间
     */
    public static final  Long expirationTime = 900L;

    public static void main(String[] args) throws Exception {
    
    

        Credentials credentials = createSTSForPutObject(bucketName, ROLE_ARN, accessKeyId, accessKeySecret, expirationTime);
        System.out.println(JSON.toJSONString(credentials));
        OSS ossClient = new OSSClientBuilder().build(END_POINT, credentials.getAccessKeyId(), credentials.getAccessKeySecret(), credentials.getSecurityToken());
        ossClient.putObject(bucketName, "1.mp4", new File("C:\\Users\\Administrator\\Videos\\朝天门.mp4"));
    }

    /**
     * 创建上传临时账号
     *
     * @param bucketName
     * @param roleArn         需要授权的角色名称
     * @param accessKeyId     账号
     * @param accessKeySecret 密码
     * @param expirationTime  过期时间,单位为秒
     * @return
     */
    public static Credentials createSTSForPutObject(String bucketName, String roleArn, String accessKeyId, String accessKeySecret, Long expirationTime) throws ClientException {
    
    
        String policy = STSUtil.getPutObjectPolicy(bucketName);
        return createSTS(policy, roleArn, accessKeyId, accessKeySecret, expirationTime);
    }

    /**
     * 创建只读临时授权
     *
     * @param bucketName
     * @param roleArn         需要授权的角色名称
     * @param accessKeyId     账号
     * @param accessKeySecret 密码
     * @param expirationTime  过期时间,单位为秒
     * @return
     */
    public static Credentials createSTSForReadOnly(String bucketName, String roleArn, String accessKeyId, String accessKeySecret, Long expirationTime) throws ClientException {
    
    
        String policy = STSUtil.getOSSReadOnlyAccessPolicy(bucketName);
        return createSTS(policy, roleArn, accessKeyId, accessKeySecret, expirationTime);
    }

    /**
     * 创建STS
     *
     * @param policy          授权策略
     * @param roleArn         需要授权的角色名称
     * @param accessKeyId     账号
     * @param accessKeySecret 密码
     * @param expirationTime  过期时间,单位为秒
     * @return
     */
    private static Credentials createSTS(String policy, String roleArn, String accessKeyId, String accessKeySecret, Long expirationTime) throws ClientException {
    
    
        IClientProfile profile = DefaultProfile.getProfile(REGION_CN_HANGZHOU, accessKeyId, accessKeySecret);
        DefaultAcsClient client = new DefaultAcsClient(profile);
        final AssumeRoleRequest request = new AssumeRoleRequest();
        request.setDurationSeconds(expirationTime);
        request.setVersion(STS_API_VERSION);
        request.setMethod(MethodType.POST);
        request.setProtocol(PROTOCOL_TYPE);
        request.setRoleArn(roleArn);
        request.setRoleSessionName(ROLE_SESSION_NAME);
        request.setPolicy(policy);
        //实体用户获取角色身份的安全令牌的方法
        AssumeRoleResponse response = client.getAcsResponse(request);
        Credentials credentials = response.getCredentials();
        return credentials;
    }

    /**
     * 自定义授权策略,对当前bucket下的文件夹读写
     *
     * @param bucketName
     * @return
     */
    private static String getPutObjectPolicy(String bucketName) {
    
    
        return String.format(
                "{\n" +
                        "    \"Version\": \"1\", \n" +
                        "    \"Statement\": [\n" +
                        "        {\n" +
                        "            \"Action\": [\n" +
                        "                \"oss:PutObject\" \n" +
                        "            ], \n" +
                        "            \"Resource\": [\n" +
                        "                \"acs:oss:*:*:%s/*\"\n" +
                        "            ], \n" +
                        "            \"Effect\": \"Allow\"\n" +
                        "        }\n" +
                        "    ]\n" +
                        "}", bucketName);
    }

    /**
     * 只读访问该bucket对象存储服务(OSS)的权限,授权策略
     *
     * @param bucketName
     * @return
     */
    private static String getOSSReadOnlyAccessPolicy(String bucketName) {
    
    
        return String.format("{\n" +
                "  \"Statement\": [\n" +
                "    {\n" +
                "      \"Action\": [\n" +
                "        \"oss:Get*\",\n" +
                "        \"oss:List*\"\n" +
                "      ],\n" +
                "      \"Effect\": \"Allow\",\n" +
                "      \"Resource\": [\n" +
                "        \"acs:oss:*:*:%s/*\"\n" +
                "      ]\n" +
                "    }\n" +
                "  ],\n" +
                "  \"Version\": \"1\"\n" +
                "}", bucketName);
    }

}

Guess you like

Origin blog.csdn.net/whzhaochao/article/details/115200160