阿里云存储OSS服务端签名客户端直传

时间:2024-02-25 10:59:15

1、阿里云存储服务端生成签名

    public class OssHelper
    {
        internal class PolicyConfig
        {
            public string expiration { get; set; }
            public List<List<Object>> conditions { get; set; }
        }

        internal class PolicyToken
        {
            public string accessid { get; set; }
            public string policy { get; set; }
            public string signature { get; set; }
            public string dir { get; set; }
            public string host { get; set; }
            public string expire { get; set; }
            public string callback { get; set; }
        }

        internal class CallbackParam
        {
            public string callbackUrl { get; set; }
            public string callbackBody { get; set; }
            public string callbackBodyType { get; set; }
        }

        // 请填写您的AccessKeyId。
        public static string accessKeyId = "";
        // 请填写您的AccessKeySecret。
        public static string accessKeySecret = "";
        // host的格式为 bucketname.endpoint ,请替换为您的真实信息。
        public static string host = "my-demo-bucket.oss-cn-hangzhou.aliyuncs.com";
        // callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
        public static string callbackUrl = "http://88.88.88.88:8888";
        // 用户上传文件时指定的前缀。
        public static string uploadDir = "user-dir-prefix/";
        public static int expireTime = 30;

        public static object GetPolicyToken()
        {
            //expireTime
            var expireDateTime = DateTime.Now.AddSeconds(expireTime);

            // example of policy
            //{
            //  "expiration": "2020-05-01T12:00:00.000Z",
            //  "conditions": [
            //    ["content-length-range", 0, 1048576000]
            //    ["starts-with", "$key", "user-dir-prefix/"]
            //  ]
            //}

            //policy
            var config = new PolicyConfig();
            config.expiration = FormatIso8601Date(expireDateTime);
            config.conditions = new List<List<Object>>();
            config.conditions.Add(new List<Object>());
            config.conditions[0].Add("content-length-range");
            config.conditions[0].Add(0);
            config.conditions[0].Add(1048576000);
            config.conditions.Add(new List<Object>());
            config.conditions[1].Add("starts-with");
            config.conditions[1].Add("$key");
            config.conditions[1].Add(uploadDir);

            var policy = JsonConvert.SerializeObject(config);
            var policy_base64 = EncodeBase64("utf-8", policy);
            var signature = ComputeSignature(accessKeySecret, policy_base64);

            //callback
            var callback = new CallbackParam();
            callback.callbackUrl = callbackUrl;
            callback.callbackBody = "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}";
            callback.callbackBodyType = "application/x-www-form-urlencoded";

            var callback_string = JsonConvert.SerializeObject(callback);
            var callback_string_base64 = EncodeBase64("utf-8", callback_string);

            var policyToken = new PolicyToken();

            policyToken.accessid = accessKeyId;
            policyToken.host = host;
            policyToken.policy = policy_base64;
            policyToken.signature = signature;
            policyToken.expire = ToUnixTime(expireDateTime);
            policyToken.callback = callback_string_base64;
            policyToken.dir = uploadDir;

            return policyToken;
            //return JsonConvert.SerializeObject(policyToken);
        }

        private static string FormatIso8601Date(DateTime dtime)
        {
            return dtime.ToUniversalTime().ToString("yyyy-MM-dd\'T\'HH:mm:ss.fff\'Z\'",
                               CultureInfo.CurrentCulture);
        }

        private static string EncodeBase64(string code_type, string code)
        {
            string encode = "";
            byte[] bytes = Encoding.GetEncoding(code_type).GetBytes(code);
            try
            {
                encode = Convert.ToBase64String(bytes);
            }
            catch
            {
                encode = code;
            }
            return encode;
        }

        private static string ComputeSignature(string key, string data)
        {
            using (var algorithm = new HMACSHA1())
            {
                algorithm.Key = Encoding.UTF8.GetBytes(key.ToCharArray());
                return Convert.ToBase64String(
                    algorithm.ComputeHash(Encoding.UTF8.GetBytes(data.ToCharArray())));
            }
        }

        private static string ToUnixTime(DateTime dtime)
        {
            const long ticksOf1970 = 621355968000000000;
            var expires = ((dtime.ToUniversalTime().Ticks - ticksOf1970) / 10000000L)
                .ToString(CultureInfo.InvariantCulture);

            return expires;
        }
    }

 

2、客户端调用

$(\'#file\').change(function () {
                var file = $(this).get(0).files[0];
                $.ajax({
                    url: \'/api/oss/GetPolicyToken\',
                    type: \'get\',
                    dataType: \'json\',
                    success: sign => {
                        //这里使用服务器签名方式,假设已经拿到服务器签名信息
                        let _date = new Date() * 1;

                        let data = new FormData();
                        data.append("Filename", `${sign.dir}${file.name}`);
                        data.append("key", `${sign.dir}${file.name}`);
                        data.append("policy", sign.policy);
                        data.append("OSSAccessKeyId", sign.accessid);
                        data.append("success_action_status", 200);
                        data.append("signature", sign.signature);
                        data.append(\'file\', file, file.name);

                        $.ajax({
                            url: \'https://\'+sign.host,
                            type: \'POST\',
                            processData: false,
                            contentType: false,
                            data: data,
                            success: result => {
                                console.log(result)
                            }
                        })
                    }
                })
            })

 

3、阿里云控制台OSS设置,允许跨域。

 

 客户端直接上传节省了服务器带宽和性能,提升客户体验。