腾讯官方没有提供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(); } } }