腾讯云兑现存储获取临时授权C#版

2019/02/27 15:35
阅读数 81

腾讯官方没有提供C#版的,没办法自己根据java版改写了一个,这里面的坑花了我20多个小时,所以记录下

<%@ WebHandler Language="C#" Class="YZCosServices" %>

using System;
using System.Web;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;
using BPM;
using BPM.Client;
using YZSoft.Web.DAL;
using Newtonsoft.Json.Linq;


public class YZCosServices : YZServiceHandler
{
    public static string SecretId = "xx";
    public static string SecretKey = "xx";
    public static string bucket = "app-1255562498";
    public static string region = "chengdu";
    public static int durationSeconds = 1800;

    public JObject GetAuth(HttpContext context)
    {
        JObject credential = new JObject();;
        try
        {
            YZRequest request = new YZRequest(context);
            SortedList<String, Object> config = new SortedList<String, Object>();
            // 固定密钥
            config.Add("SecretId", SecretId);
            // 固定密钥
            config.Add("SecretKey", SecretKey);

            // 临时密钥有效时长,单位是秒
            config.Add("durationSeconds", durationSeconds);

            // 换成你的 bucket
            config.Add("bucket", bucket);
            // 换成 bucket 所在地区
            config.Add("region", region);

            // 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的目录,例子:* 或者 a/* 或者 a.jpg
            config.Add("allowPrefix", "*");

            // 密钥的权限列表。简单上传和分片需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
            String[] allowActions = new String[] {
                "*"
                /*
                    // 简单上传
                    "name/cos:PutObject",
                    // 分片上传
                    "name/cos:InitiateMultipartUpload",
                    "name/cos:ListMultipartUploads",
                    "name/cos:ListParts",
                    "name/cos:UploadPart",
                    "name/cos:CompleteMultipartUpload"
                    */
            };
            config.Add("allowActions", allowActions);

            string result = getCredential(config);
            credential.Add("status", true);
            credential.Add("data", result);
        }
        catch (Exception e) {
            credential.Add("status", false);
            credential.Add("errMsg"+e.Message);
        }

        return credential;

    }

    public static string getCredential(SortedList<string, object> config)  {
        SortedList<string, object> params1 = new SortedList<string, object>();

        if (config.ContainsKey("policy"))
        {
            string policy = (string)config["policy"];
            if (policy != null)
            {
                params1.Add("Policy", policy);
            }
            else
            {
                params1.Add("Policy", getPolicy(config));
            }
        }
        else {
            params1.Add("Policy", getPolicy(config));
        }


        int durationSeconds = 1800;
        if (config["durationSeconds"] != null) {
            durationSeconds = (Int32) config["durationSeconds"];
        }
        params1.Add("DurationSeconds", durationSeconds);

        params1.Add("Name", "cos-sts-donet");
        params1.Add("Action", "GetFederationToken");
        params1.Add("Version", "2018-08-13");
        params1.Add("Region", "ap-guangzhou");

        string host = "sts.tencentcloudapi.com";
        string path = "/";

        string result = null;
        try {
            result = send(params1, (string) config["SecretId"],
                    config["SecretKey"].ToString(),
                    "POST", host, path);

            /*
               JObject jsonResult = new JObject( );
               JObject data = (JObject)jsonResult["Response"];
               if (data == null) {
                   data = jsonResult;
               }
               Int64 expiredTime = Convert.ToInt64(data["ExpiredTime"]);
               data.Add("startTime", expiredTime - durationSeconds);
               return downCompat(data);
          */

        } catch (Exception e) {
            throw new Exception("result = " + result, e);
        }
        return result;
    }

    public static string getPolicy(List<Scope> scopes) {
        if(scopes == null || scopes.Count == 0)return null;
        STSPolicy stsPolicy = new STSPolicy();
        stsPolicy.addScope(scopes);
        return stsPolicy.ToString();
    }

    // v2接口的key首字母小写,v3改成大写,此处做了向下兼容
    private static JObject downCompat(JObject resultJson) {
        JObject dcJson = new JObject();

        foreach (var item in dcJson)
        {
            object value = item.Value;
            if (value is JObject)
            {
                dcJson.Add(headerToLowerCase(item.Key), downCompat((JObject)value));
            }
            else
            {
                string newKey = "Token" == item.Key ? "sessionToken" : headerToLowerCase(item.Key);
                dcJson.Add(newKey, item.Value);
            }

        }
        return dcJson;
    }

    private static string headerToLowerCase(string source) {
        return source.Substring(0 - 1).ToLower() + source.Substring(1);
    }

    private static string getPolicy(SortedList<string, object> config) {
        string bucket = (string) config["bucket"];
        string region = (string) config["region"];
        string allowPrefix = (string) config["allowPrefix"];
        string[] allowActions = (string[]) config["allowActions"];

        JObject principal = new JObject();
        principal.Add("qcs", "*");

        int lastSplit = bucket.LastIndexOf("-");
        string shortBucketName = bucket.Substring(0, lastSplit);
        string appId = bucket.Substring(lastSplit + 1);

        string resource = string.Format("qcs::cos:{0}:uid/{1}:prefix//{2}/{3}/{4}",
                region, appId, appId, shortBucketName, allowPrefix);


        JArray actions = new  JArray();
        foreach(var action in allowActions) {
            actions.Add(action);
        }
       
        JObject policy = new JObject();

        JObject statement = new JObject();
        statement.Add("principal", principal);
        statement.Add("resource", resource);
        statement.Add("effect", "allow");
        statement.Add("action", actions);

        policy.Add("statement", statement);
        policy.Add("version", "2.0");
        
       
        return  Newtonsoft.Json.JsonConvert.SerializeObject(policy);

    }

    /// <summary>
    /// 准备发送请求
    /// </summary>
    /// <param name="params1"></param>
    /// <param name="secretId"></param>
    /// <param name="secretKey"></param>
    /// <param name="requestMethod"></param>
    /// <param name="requestHost"></param>
    /// <param name="requestPath"></param>
    /// <returns></returns>
    public static string send(SortedList<string, object> params1, string secretId,
            string secretKey, string requestMethod, string requestHost,
            string requestPath) {
        if (!params1.ContainsKey("SecretId"))
            params1.Add("SecretId", secretId);

        if (!params1.ContainsKey("Nonce"))
            params1.Add("Nonce",new Random().Next(Int32.MaxValue));
            //params1.Add("Nonce",829042144);

        if (!params1.ContainsKey("Timestamp"))
           params1.Add("Timestamp", ConvertDataTimeToLong(DateTime.Now) / 1000);
           // params1.Add("Timestamp", 1551241700);

        params1.Remove("Signature");
        string plainText = makeSignPlainText(params1, requestMethod,
                requestHost, requestPath);

        string signatureMethod = "HmacSHA1";
        if (params1.ContainsKey("SignatureMethod") && params1["SignatureMethod"].ToString() == "HmacSHA256")
        {
            signatureMethod = "HmacSHA256";
        }

        String signStr = sign(plainText, secretKey, signatureMethod);

        
        System.IO.File.WriteAllLines(@"d:\test2.txt", new string[]{ plainText+"\r\n"+signStr}, Encoding.UTF8);

        params1.Add("Signature", signStr); 


        string url = "https://" + requestHost + requestPath;


        return sendRequest(url, params1, requestMethod);
    }

    /// <summary>
    /// 发送请求
    /// </summary>
    /// <param name="url"></param>
    /// <param name="requestParams"></param>
    /// <param name="requestMethod"></param>
    /// <returns></returns>
    public static String sendRequest(String url, SortedList<string, object> requestParams, String requestMethod) {
        String result = "";
        String paramStr = "";

        foreach (var item in requestParams) {
            if (!string.IsNullOrEmpty(paramStr)) {
                paramStr += '&';
            }

            paramStr += item.Key + '='
                    +XUrlEncode(item.Value.ToString());

        }

        if (requestMethod=="GET") {
            if (url.IndexOf('?') > 0) {
                url += '&' + paramStr;
            } else {
                url += '?' + paramStr;
            }
        }
        string requestUrl = url;
        String BOUNDARY = "---------------------------"
                + EnMD5(ConvertDataTimeToLong(DateTime.Now)+"")
                        .Substring(0, 15);



        System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckCertificate);
        System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(requestUrl);
        request.Accept = "*/*";
        request.KeepAlive = true;
        request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)";
        // 设置链接主机超时时间
        request.Timeout = 90000;
        request.ReadWriteTimeout = 90000;
        request.Expect = null;

        System.Net.WebProxy proxy = new System.Net.WebProxy();                                      //定義一個網關對象
        proxy.Address = new Uri("http://127.0.0.1:8888");              //網關服務器:端口
        request.Proxy = proxy;

        if (requestMethod=="POST") {
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            byte[] buffer = Encoding.UTF8.GetBytes(paramStr);
            request.ContentLength = buffer.Length;
            request.GetRequestStream().Write(buffer, 0, buffer.Length);
            request.GetRequestStream().Close();
        }



        System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
        System.IO.Stream stream = response.GetResponseStream();
        System.IO.StreamReader sr = new System.IO.StreamReader(stream, Encoding.UTF8);
        result = sr.ReadToEnd();

        return result;
    }

    /// <summary>
    /// 天坑,这里urlcode的到的转码字母是小写,java平台得到的转码字母是大写,所以需要转换成小写。
    /// 当然腾讯运平台估计也是用的小写
    /// 不然验证不会通不过。
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static string XUrlEncode(string str)
    {
        StringBuilder builder = new StringBuilder();
        foreach (char c in str)
        {
            if (HttpUtility.UrlEncode(c.ToString()).Length > 1)
            {
                builder.Append(HttpUtility.UrlEncode(c.ToString(),System.Text.Encoding.UTF8).ToUpper());
            }
            else
            {
                builder.Append(c);
            }
        }
        return builder.ToString();
    }

    /// <summary>
    /// 获取unix的时间戳
    /// </summary>
    /// <param name="dt"></param>
    /// <returns></returns>
    public static long ConvertDataTimeToLong(DateTime dt)
    {

        DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
        TimeSpan toNow = dt.Subtract(dtStart);
        long timeStamp = toNow.Ticks;
        timeStamp = long.Parse(timeStamp.ToString().Substring(0, timeStamp.ToString().Length - 4));
        return timeStamp;

        //return 1551183028000l;
    }
    
    /// <summary>
    /// md5签名
    /// </summary>
    /// <param name="text"></param>
    /// <returns></returns>
    public static string EnMD5(string text) {
        System.Security.Cryptography.MD5 md5Hasher = System.Security.Cryptography.MD5.Create();
        byte[] data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(text));
        return Convert.ToBase64String(data);

    }

    /// <summary>
    /// 构建待加密的明文文本
    /// </summary>
    /// <param name="requestParams"></param>
    /// <param name="requestMethod"></param>
    /// <param name="requestHost"></param>
    /// <param name="requestPath"></param>
    /// <returns></returns>
    public static String makeSignPlainText(SortedList<String, Object> requestParams, String requestMethod, String requestHost, String requestPath) {

        String retStr = "";
        retStr += requestMethod;
        retStr += requestHost;
        retStr += requestPath;
        retStr += buildParamStr(requestParams, requestMethod);
        return retStr;
    }

    /// <summary>
    /// 检测证书
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="certificate"></param>
    /// <param name="chain"></param>
    /// <param name="errors"></param>
    /// <returns></returns>
    private static bool CheckCertificate(object sender,
        System.Security.Cryptography.X509Certificates.X509Certificate certificate,
        System.Security.Cryptography.X509Certificates.X509Chain chain,
        System.Net.Security.SslPolicyErrors errors)
    {
        return true;
    }

    /// <summary>
    /// 构建待加密的明文文本
    /// </summary>
    /// <param name="requestParams"></param>
    /// <param name="requestMethod"></param>
    /// <returns></returns>
    protected static String buildParamStr(SortedList<String, Object> requestParams, String requestMethod) {

        String retStr = "";
        foreach(var item in requestParams) {
            String value = item.Value.ToString();
            //排除上传文件的参数
            if("POST"==requestMethod && (! string.IsNullOrEmpty(value)) && value.Substring(0, 1)=="@"){
                continue;
            }
            if (retStr.Length==0) {
                retStr += '?';
            } else {
                retStr += '&';
            }
            retStr += item.Key.Replace("_", ".") + '=' + value;

        }
        return retStr;
    }

    /**
     * 签名
     * @author cicerochen@tencent.com
     *
     * @param signStr 被加密串
     * @param secret 加密密钥
     * @param signatureMethod 签名算法
     *
     * @return 签名结果
     */
    public static String sign(String signStr, String secret, String signatureMethod)
    {

        byte[] keyByte = Encoding.UTF8.GetBytes(secret);
        byte[] messageBytes = Encoding.UTF8.GetBytes(signStr);
        if (signatureMethod == "HmacSHA256")
        {
            using (var hmacsha256 = new System.Security.Cryptography.HMACSHA256(keyByte))
            {
                hmacsha256.Initialize();
                byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
                return Convert.ToBase64String(hashmessage);
            }
        } else {
            using (var hmacsha1 = new System.Security.Cryptography.HMACSHA1(keyByte))
            {
                hmacsha1.Initialize();
                byte[] hashmessage = hmacsha1.ComputeHash(messageBytes);
                return Convert.ToBase64String(hashmessage);
            }
        }

    }

    public class STSPolicy {

        private List<Scope> scopes = new List<Scope>();

        public STSPolicy() {

        }

        public void addScope(List<Scope> scopes) {
            if (scopes != null) {
                foreach (Scope scope in scopes) {
                    this.scopes.Add(scope);
                }
            }
        }

        public void addScope(Scope scope) {
            this.scopes.Add(scope);
        }

        private SortedList<string,Object> createElement(Scope scope) {

            SortedList<string,Object> principal = new  SortedList<string,Object>();
            List<Object> qcs = new List<Object>();
            qcs.Add("*");
            principal.Add("qcs", qcs);

            List<Object> resources = new List<Object>();
            resources.Add(scope.getResource());

            List<Object> actions = new List<Object>();
            actions.Add(scope.getAction());

            SortedList<string,Object> element = new  SortedList<string,Object>();
            element.Add("principal", principal);
            element.Add("resource", resources);
            element.Add("effect", "allow");
            element.Add("action", actions);

            System.IO.File.WriteAllLines(@"d:\test1.txt", new string[]{ Newtonsoft.Json.JsonConvert.SerializeObject(element)}, Encoding.UTF8);

            return element;
        }


        public override String ToString() {
            SortedList<string,Object> policy = new SortedList<string,Object>();
            policy.Add("version", "2.0");
            List<Object> statement = new List<Object>();
            if (scopes.Count > 0) {
                foreach (Scope scope in scopes) {
                    statement.Add(createElement(scope));
                }
                policy.Add("statement", statement);
            }
            return Newtonsoft.Json.JsonConvert.SerializeObject(policy);
        }
    }

    public class Scope {

        private String action;
        private String bucket;
        private String region;
        private String sourcePrefix;

        /**
         * 
         * @param action 操作名称,如 "name/cos:PutObject"
         * @param bucket 存储桶名称,格式:test-1250000000
         * @param region 园区名称,如 ap-guangzhou
         * @param prefix 拼接 resource 字段所需的 key 前缀,客户端 SDK 默认传固定文件名如 "dir/1.txt",支持 * 结尾如 "dir/*"
         */
        public Scope(String action, String bucket, String region, String sourcePrefix) {
            this.action = action;
            this.bucket = bucket;
            this.region = region;
            this.sourcePrefix = sourcePrefix;
        }

        public void setBucket(String bucket) {
            this.bucket = bucket;
        }

        public void setRegion(String region) {
            this.region = region;
        }

        public void setAction(String action) {
            this.action = action;
        }

        public void setResourcePrefix(String sourcePrefix) {
            this.sourcePrefix = sourcePrefix;
        }

        public String getAction() {
            return this.action;
        }

        public String getResource() {
            int index = bucket.LastIndexOf('-');
            String appid = bucket.Substring(index + 1).Trim();
            String bucketName = bucket.Substring(0, index).Trim();
            if(!sourcePrefix.StartsWith("/")) {
                sourcePrefix = '/' + sourcePrefix;
            }
            StringBuilder resource = new StringBuilder();
            resource.Append("qcs::cos")
                .Append(':')
                .Append(region)
                .Append(':')
                .Append("uid/").Append(appid)
                .Append(':')
                .Append("prefix//").Append(appid).Append('/').Append(bucketName)
                .Append(sourcePrefix);
            return resource.ToString();
        }

    }

}

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部