|
@@ -0,0 +1,288 @@
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Diagnostics;
|
|
|
+using System.Linq;
|
|
|
+using System.Security.Cryptography;
|
|
|
+using System.Text;
|
|
|
+
|
|
|
+namespace TEAMModelOS.Controllers.Third.Xkw
|
|
|
+{
|
|
|
+ public class HmacUtils
|
|
|
+ {
|
|
|
+ /// <summary>
|
|
|
+ /// Java的System.currentTimeMillis()转成C#的
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ public static long GetCurrentTimeMillis()
|
|
|
+ {
|
|
|
+ return (DateTime.UtcNow.Ticks - 621355968000000000L) / 10000 / 1000;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static HmacResult Sign(String appId, String secret, Dictionary<String, String> parameters, String requestBodyStr)
|
|
|
+ {
|
|
|
+ Dictionary<String, String> dic = CopyDictionary(parameters);
|
|
|
+ //
|
|
|
+ long timeStamp = GetCurrentTimeMillis();
|
|
|
+ dic.Add(HmacConst.KEY_TIMESTAMP, timeStamp.ToString());
|
|
|
+ dic.Add(HmacConst.KEY_APP_ID, appId);
|
|
|
+ //去掉传递过来的sign
|
|
|
+ dic.Remove(HmacConst.KEY_SIGN);
|
|
|
+ //去掉传递过来的nonce,一律在此统一放入
|
|
|
+ dic.Remove(HmacConst.KEY_NONCE);
|
|
|
+ String nonce = Guid.NewGuid().ToString("").Replace("-", "");
|
|
|
+ dic.Add(HmacConst.KEY_NONCE, nonce);
|
|
|
+
|
|
|
+ String sha1Str = GetSignatureString(dic, secret, requestBodyStr);
|
|
|
+ dic.Add(HmacConst.KEY_SIGN, sha1Str);
|
|
|
+ return new HmacResult(timeStamp, sha1Str, nonce);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public static bool ValidateRequestTimestamp(String timestampStr, long maxTimestampGap)
|
|
|
+ {
|
|
|
+ // validate the timestamp
|
|
|
+ long timeStamp = long.Parse(timestampStr);
|
|
|
+ long timeStampNow = GetCurrentTimeMillis();
|
|
|
+ return Math.Abs(timeStamp - timeStampNow) < maxTimestampGap;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static bool ValidateRequest(Dictionary<string, string> parameters, string secret, string requestBodyStr)
|
|
|
+ {
|
|
|
+ Dictionary<string, string> dic = CopyDictionary(parameters);
|
|
|
+
|
|
|
+ // get AccessTokenId, sign
|
|
|
+ string sign = null;
|
|
|
+ if (dic.ContainsKey(HmacConst.KEY_SIGN))
|
|
|
+ {
|
|
|
+ sign = dic[HmacConst.KEY_SIGN];
|
|
|
+ dic.Remove(HmacConst.KEY_SIGN);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ string md5Str = GetSignatureString(dic, secret, requestBodyStr);
|
|
|
+ return md5Str.Equals(sign, StringComparison.OrdinalIgnoreCase);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static string GetSignatureString(Dictionary<string, string> dic, string secret, string requestBodyStr)
|
|
|
+ {
|
|
|
+ Dictionary<string, string> tempDic = CopyDictionary(dic);
|
|
|
+
|
|
|
+ if (!String.IsNullOrEmpty(requestBodyStr))
|
|
|
+ {
|
|
|
+ tempDic.Add(HmacConst.REQUEST_BODY, requestBodyStr);
|
|
|
+ }
|
|
|
+
|
|
|
+ String sortParamStr = GenerateQueryString(tempDic);
|
|
|
+
|
|
|
+ //下面的bapi的签名,xop没使用url编码了
|
|
|
+ //StringBuilder sb = new StringBuilder();
|
|
|
+ //foreach (string key in keyList)
|
|
|
+ //{
|
|
|
+ // string value = dic[key];
|
|
|
+ // if (value == null)
|
|
|
+ // {
|
|
|
+ // continue;
|
|
|
+ // }
|
|
|
+ // sb.Append(key);
|
|
|
+ // sb.Append("=");
|
|
|
+ // sb.Append(FormatString(value));
|
|
|
+ // sb.Append("&");
|
|
|
+ //}
|
|
|
+ //sb.Append("secret=");
|
|
|
+ //sb.Append(secret);
|
|
|
+ //string keyListStr = sb.ToString();
|
|
|
+
|
|
|
+
|
|
|
+ String keyListStr = sortParamStr + "&secret=" + secret;
|
|
|
+ byte[] inputBytes = Encoding.UTF8.GetBytes(keyListStr);
|
|
|
+ string base64Str = Convert.ToBase64String(inputBytes);
|
|
|
+ byte[] bytes = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(base64Str));
|
|
|
+ return BitConverter.ToString(bytes).Replace("-", "").ToLower();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static String GenerateQueryString(Dictionary<String, String> dic)
|
|
|
+ {
|
|
|
+ List<string> sortedKeyList = dic.Keys.OrderBy(i => i, StringComparer.Ordinal).ToList();
|
|
|
+ List<String> tempParams = new List<string>(dic.Count);
|
|
|
+ foreach (var key in sortedKeyList)
|
|
|
+ {
|
|
|
+ String str = key + "=" + dic[key];
|
|
|
+ tempParams.Add(str);
|
|
|
+ }
|
|
|
+ return String.Join("&", tempParams);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Dictionary<string, string> CopyDictionary(Dictionary<string, string> dic)
|
|
|
+ {
|
|
|
+ Dictionary<string, string> copyDic = new Dictionary<string, string>();
|
|
|
+ if (dic == null || dic.Count == 0)
|
|
|
+ {
|
|
|
+ return copyDic;
|
|
|
+ }
|
|
|
+ foreach (var item in dic)
|
|
|
+ {
|
|
|
+ copyDic.Add(item.Key, item.Value);
|
|
|
+ }
|
|
|
+ return copyDic;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ class UrlEncode
|
|
|
+ {
|
|
|
+ const int caseDiff = ('a' - 'A');
|
|
|
+ private static bool ValidateUrlEncodingParameters(byte[] bytes, int offset, int count)
|
|
|
+ {
|
|
|
+ if (bytes == null && count == 0)
|
|
|
+ return false;
|
|
|
+ if (bytes == null)
|
|
|
+ {
|
|
|
+ throw new ArgumentNullException("bytes");
|
|
|
+ }
|
|
|
+ if (offset < 0 || offset > bytes.Length)
|
|
|
+ {
|
|
|
+ throw new ArgumentOutOfRangeException("offset");
|
|
|
+ }
|
|
|
+ if (count < 0 || offset + count > bytes.Length)
|
|
|
+ {
|
|
|
+ throw new ArgumentOutOfRangeException("count");
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ public static string Encode(string str, Encoding e)
|
|
|
+ {
|
|
|
+ if (str == null)
|
|
|
+ return null;
|
|
|
+
|
|
|
+ byte[] bytes = e.GetBytes(str);
|
|
|
+ int offset = 0;
|
|
|
+ int count = bytes.Length;
|
|
|
+
|
|
|
+ if (!ValidateUrlEncodingParameters(bytes, offset, count))
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ int cSpaces = 0;
|
|
|
+ int cUnsafe = 0;
|
|
|
+
|
|
|
+ // count them first
|
|
|
+ for (int i = 0; i < count; i++)
|
|
|
+ {
|
|
|
+ char ch = (char)bytes[offset + i];
|
|
|
+
|
|
|
+ if (ch == ' ')
|
|
|
+ cSpaces++;
|
|
|
+ else if (!HttpEncoderUtility.IsUrlSafeChar(ch))
|
|
|
+ cUnsafe++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // nothing to expand?
|
|
|
+ if (cSpaces == 0 && cUnsafe == 0)
|
|
|
+ {
|
|
|
+ // DevDiv 912606: respect "offset" and "count"
|
|
|
+ if (0 == offset && bytes.Length == count)
|
|
|
+ {
|
|
|
+ return Encoding.ASCII.GetString(bytes);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var subarray = new byte[count];
|
|
|
+ Buffer.BlockCopy(bytes, offset, subarray, 0, count);
|
|
|
+ return Encoding.ASCII.GetString(subarray);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // expand not 'safe' characters into %XX, spaces to +s
|
|
|
+ byte[] expandedBytes = new byte[count + cUnsafe * 2];
|
|
|
+ int pos = 0;
|
|
|
+
|
|
|
+ for (int i = 0; i < count; i++)
|
|
|
+ {
|
|
|
+ byte b = bytes[offset + i];
|
|
|
+ char ch = (char)b;
|
|
|
+
|
|
|
+ if (HttpEncoderUtility.IsUrlSafeChar(ch))
|
|
|
+ {
|
|
|
+ expandedBytes[pos++] = b;
|
|
|
+ }
|
|
|
+ else if (ch == ' ')
|
|
|
+ {
|
|
|
+ expandedBytes[pos++] = (byte)'+';
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ expandedBytes[pos++] = (byte)'%';
|
|
|
+ ch = (char)HttpEncoderUtility.IntToHex((b >> 4) & 0xF);
|
|
|
+ if (char.IsLetter(ch))
|
|
|
+ {
|
|
|
+ ch = (char)((int)ch - caseDiff);
|
|
|
+ }
|
|
|
+
|
|
|
+ expandedBytes[pos++] = (byte)ch;
|
|
|
+
|
|
|
+ ch = HttpEncoderUtility.IntToHex(b & 0x0F);
|
|
|
+ if (char.IsLetter(ch))
|
|
|
+ {
|
|
|
+ ch = (char)((int)ch - caseDiff);
|
|
|
+ }
|
|
|
+
|
|
|
+ expandedBytes[pos++] = (byte)ch;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Encoding.ASCII.GetString(expandedBytes);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ class HttpEncoderUtility
|
|
|
+ {
|
|
|
+ public static char IntToHex(int n)
|
|
|
+ {
|
|
|
+ Debug.Assert(n < 0x10);
|
|
|
+
|
|
|
+ if (n <= 9)
|
|
|
+ return (char)(n + (int)'0');
|
|
|
+ else
|
|
|
+ return (char)(n - 10 + (int)'a');
|
|
|
+ }
|
|
|
+
|
|
|
+ // Set of safe chars, from RFC 1738.4 minus '+'
|
|
|
+ public static bool IsUrlSafeChar(char ch)
|
|
|
+ {
|
|
|
+ if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ switch (ch)
|
|
|
+ {
|
|
|
+ case '-':
|
|
|
+ case '_':
|
|
|
+ case '.':
|
|
|
+ case '!':
|
|
|
+ case '*':
|
|
|
+ //JAVA t appears that both Netscape and Internet Explorer escape
|
|
|
+ //*all special characters from this list with the exception
|
|
|
+ //*of "-", "_", ".", "*".
|
|
|
+ //所以这两括号需要转义
|
|
|
+ ////case '(':
|
|
|
+ ////case ')':
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Helper to encode spaces only
|
|
|
+ internal static String UrlEncodeSpaces(string str)
|
|
|
+ {
|
|
|
+ if (str != null && str.IndexOf(' ') >= 0)
|
|
|
+ str = str.Replace(" ", "%20");
|
|
|
+ return str;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|