騰訊雲兌現存儲獲取臨時受權C#版

騰訊官方沒有提供C#版的,沒辦法本身根據java版改寫了一個,這裏面的坑花了我20多個小時,因此記錄下java

<%@ 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();
        }

    }

}
相關文章
相關標籤/搜索