OpenAuthClient.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Net;
  5. using System.Security.Cryptography;
  6. using System.Text;
  7. using System.Web;
  8. using TEAMModelOS.SDK.Extension;
  9. namespace TEAMModelOS.Controllers.Third.Xkw
  10. {
  11. public abstract class OpenAuthClient
  12. {
  13. public string ClientName { get; protected set; }
  14. public string AppKey { get; protected set; }
  15. public string AppSecret { get; protected set; }
  16. public string RedirectUrl { get; set; }
  17. public string AccessToken { get; set; }
  18. public bool IsAuthorized
  19. {
  20. get { return isAccessTokenSet && !string.IsNullOrEmpty(AccessToken); }
  21. }
  22. protected bool isAccessTokenSet = false;
  23. public abstract string GetAuthorizationUrl();
  24. public abstract void GetAccessTokenByCode(string code, string schoolId);
  25. public OpenAuthClient(string clientId, string appSecret, string redirectUrl, string accessToken = null)
  26. {
  27. this.AppKey = clientId;
  28. this.AppSecret = appSecret;
  29. this.RedirectUrl = redirectUrl;
  30. this.AccessToken = accessToken;
  31. if (!string.IsNullOrEmpty(accessToken))
  32. {
  33. isAccessTokenSet = true;
  34. }
  35. }
  36. }
  37. public class XkwOAuthClient : OpenAuthClient
  38. {
  39. public string Domain { get; set; }
  40. public string AUTH_HOST { get; set; }
  41. public string AUTH_URL { get; set; }
  42. public string TOKEN_URL { get; set; }
  43. public string PROFILE_URL { get; set; }
  44. public string SERVICE_URL { get; set; }
  45. public string OpenId { get; set; }
  46. public string UserId { get; set; }
  47. public string Param { get; set; }
  48. /// <summary>
  49. /// 静默注册参数
  50. /// </summary>
  51. public string Extra { get; set; }
  52. public string ErrorMessage { get; set; }
  53. public XkwOAuthClient(string appKey, string appSecret, string redirectUrl, string oauthHost, string domain, string accessToken = null, string openid = null, string userId = null, string param = null)
  54. : base(appKey, appSecret, redirectUrl, accessToken)
  55. {
  56. ClientName = "Xkw Demo Client";
  57. OpenId = openid;
  58. UserId = userId;
  59. AUTH_HOST = oauthHost;
  60. AUTH_URL = AUTH_HOST + "authorize";
  61. TOKEN_URL = AUTH_HOST + "accessToken";
  62. PROFILE_URL = AUTH_HOST + "profile";
  63. Domain = domain;
  64. if (!(string.IsNullOrEmpty(accessToken) && string.IsNullOrEmpty(openid)))
  65. {
  66. isAccessTokenSet = true;
  67. }
  68. Param = param;
  69. }
  70. /// <summary>
  71. /// 进行认证
  72. /// </summary>
  73. /// <returns></returns>
  74. public override string GetAuthorizationUrl()
  75. {
  76. string redirect_uri= $"http://kong.sso.com:5000/authorized/xkw?{HttpUtility.UrlEncode(Param) }";
  77. string openSecret = "";
  78. if (!string.IsNullOrEmpty(OpenId))
  79. {
  80. openSecret = CryptoUtils.EncryptAES(OpenId, AppSecret);
  81. }
  82. string timespan = CryptoUtils.EncryptAES(GetTimeStamp(), AppSecret);
  83. string url = string.Format(AUTH_URL + "?client_id={0}&open_id={1}&service={2}&redirect_uri={3}&timespan={4}",
  84. AppKey, openSecret, SERVICE_URL, redirect_uri, timespan);
  85. if (!string.IsNullOrEmpty(Extra))
  86. {
  87. url = string.Format("{0}&extra={1}", url, Extra);
  88. }
  89. //string retUrl = url + "&signature=" + SignatureHelper.GenerateSignature(url, AppSecret);
  90. string URLEncoder = string.Format(AUTH_URL + "?client_id={0}&open_id={1}&service={2}&redirect_uri={3}&timespan={4}&extra={5}&signature={6}",
  91. HttpUtility.UrlEncode(AppKey), HttpUtility.UrlEncode(openSecret), HttpUtility.UrlEncode(SERVICE_URL), HttpUtility.UrlEncode(redirect_uri),
  92. HttpUtility.UrlEncode(timespan), HttpUtility.UrlEncode(Extra), HttpUtility.UrlEncode(SignatureHelper.GenerateSignature(url, AppSecret)));
  93. return URLEncoder.Replace("+", "%2B");
  94. }
  95. /// <summary>
  96. /// 根据code获取accessToken和用户信息
  97. /// </summary>
  98. /// <param name="code">code</param>
  99. /// <param name="schoolId">学校ID</param>
  100. public override void GetAccessTokenByCode(string code, string schoolId = null)
  101. {
  102. var client = new WebClient();
  103. client.Encoding = System.Text.Encoding.UTF8;
  104. try
  105. {
  106. //验证服务器证书回调自动验证
  107. ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
  108. string url = string.Format(TOKEN_URL + "?client_id={0}&code={1}&redirect_uri={2}", AppKey, code, RedirectUrl);
  109. string retUrl = url + "&signature=" + SignatureHelper.GenerateSignature(url, AppSecret);
  110. string data = client.DownloadString(retUrl);
  111. IDictionary<string, object> access_token_dic = data.ToObject<IDictionary<string, object>>();
  112. if (access_token_dic.ContainsKey("access_token"))
  113. AccessToken = $"{access_token_dic["access_token"]}";
  114. //获取用户openid
  115. string userProfileUrl = string.Format(PROFILE_URL + "?access_token={0}&schoolId={1}", AccessToken, schoolId);
  116. string ret = client.DownloadString(userProfileUrl);
  117. IDictionary<string, string> openId_dic = ret.ToObject<IDictionary<string, string>>();
  118. if (openId_dic.ContainsKey("open_id"))
  119. {
  120. OpenId = openId_dic["open_id"];
  121. }
  122. if (!string.IsNullOrEmpty(OpenId))
  123. {
  124. isAccessTokenSet = true;
  125. }
  126. else
  127. {
  128. if (openId_dic.ContainsKey("error"))
  129. {
  130. ErrorMessage = openId_dic["error"];
  131. }
  132. }
  133. }
  134. catch (Exception ex)
  135. {
  136. ErrorMessage = "服务器异常:" + ex.Message;
  137. }
  138. }
  139. /// <summary>
  140. /// 获取当前时间的时间戳
  141. /// </summary>
  142. /// <returns></returns>
  143. private string GetTimeStamp()
  144. {
  145. TimeSpan ts = new TimeSpan(DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1, 0, 0, 0).Ticks);
  146. return ((long)ts.TotalMilliseconds).ToString();
  147. }
  148. }
  149. class SignatureHelper
  150. {
  151. /// <summary>
  152. /// 获取参数签名
  153. /// </summary>
  154. /// <param name="url">需要生成签名的url</param>
  155. /// <returns></returns>
  156. public static string GenerateSignature(String url, String secret)
  157. {
  158. int index = url.IndexOf("?");
  159. if (index > -1)
  160. {
  161. //将参数按参数名进行排序,然后对参数值进行加密
  162. string paramStr = url.Substring(index + 1);
  163. string[] paramKeyValues = paramStr.Split('&');
  164. Array.Sort(paramKeyValues);
  165. StringBuilder paramValueStr = new StringBuilder();
  166. foreach (string param in paramKeyValues)
  167. {
  168. string[] paramKeyValue = param.Split(new char[] { '=' }, 2);
  169. paramValueStr.Append(paramKeyValue[1]);
  170. }
  171. paramValueStr.Append(secret);
  172. return CryptoUtils.EncryptMD5(paramValueStr.ToString());
  173. }
  174. return "";
  175. }
  176. /// <summary>
  177. /// 获取参数签名
  178. /// </summary>
  179. /// <param name="paramDic">参数键值对</param>
  180. /// <param name="secret">加密秘钥</param>
  181. /// <returns></returns>
  182. public static string GenerateSignature(SortedDictionary<string, string> paramDic, String secret)
  183. {
  184. if (paramDic.Count > 0)
  185. {
  186. string paramStr = string.Concat(string.Join("", paramDic.Values), secret);
  187. return CryptoUtils.EncryptMD5(paramStr);
  188. }
  189. return "";
  190. }
  191. /// <summary>
  192. /// 获取参数签名
  193. /// </summary>
  194. /// <param name="paramList">参数键值对</param>
  195. /// <param name="secret">加密秘钥</param>
  196. /// <returns></returns>
  197. public static string GenerateSignature(SortedList<string, string> paramList, String secret)
  198. {
  199. if (paramList.Count > 0)
  200. {
  201. string paramStr = string.Concat(string.Join("", paramList.Values), secret);
  202. return CryptoUtils.EncryptMD5(paramStr);
  203. }
  204. return "";
  205. }
  206. }
  207. public class CryptoUtils
  208. {
  209. /// <summary>
  210. /// MD5加密
  211. /// </summary>
  212. /// <param name="encryptString">待加密的字符串</param>
  213. /// <returns>加密过的字符串</returns>
  214. public static string EncryptMD5(string encryptString)
  215. {
  216. byte[] result = Encoding.UTF8.GetBytes(encryptString);
  217. MD5 md5 = new MD5CryptoServiceProvider();
  218. byte[] output = md5.ComputeHash(result);
  219. string encryptResult = BitConverter.ToString(output).Replace("-", "");
  220. return encryptResult;
  221. }
  222. #region AES
  223. /// <summary>
  224. /// AES加密
  225. /// </summary>
  226. /// <param name="str">待加密字符串</param>
  227. /// <returns>加密后字符串</returns>
  228. public static string EncryptAES(string str, string key)
  229. {
  230. try
  231. {
  232. //分组加密算法
  233. AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
  234. byte[] inputByteArray = Encoding.UTF8.GetBytes(str);//得到需要加密的字节数组
  235. //设置密钥及密钥向量
  236. aes.Key = Encoding.UTF8.GetBytes(key);
  237. //aes.IV = Encoding.UTF8.GetBytes(key);
  238. aes.Mode = CipherMode.ECB;
  239. aes.Padding = PaddingMode.PKCS7;
  240. byte[] cipherBytes = null;
  241. using (MemoryStream ms = new MemoryStream())
  242. {
  243. using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
  244. {
  245. cs.Write(inputByteArray, 0, inputByteArray.Length);
  246. cs.FlushFinalBlock();
  247. cipherBytes = ms.ToArray();//得到加密后的字节数组
  248. cs.Close();
  249. ms.Close();
  250. }
  251. }
  252. return Convert.ToBase64String(cipherBytes);
  253. }
  254. catch { }
  255. return str;
  256. }
  257. /// <summary>
  258. /// AES解密
  259. /// </summary>
  260. /// <param name="str">待解密字符串</param>
  261. /// <returns>解密后字符串</returns>
  262. public static string DecryptAES(string str, string key)
  263. {
  264. try
  265. {
  266. byte[] cipherText = Convert.FromBase64String(str);
  267. AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
  268. aes.Key = Encoding.UTF8.GetBytes(key);
  269. //aes.IV = Encoding.UTF8.GetBytes(key);
  270. aes.Mode = CipherMode.ECB;
  271. aes.Padding = PaddingMode.PKCS7;
  272. byte[] decryptBytes = new byte[cipherText.Length];
  273. using (MemoryStream ms = new MemoryStream(cipherText))
  274. {
  275. using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read))
  276. {
  277. cs.Read(decryptBytes, 0, decryptBytes.Length);
  278. cs.Close();
  279. ms.Close();
  280. }
  281. }
  282. return Encoding.UTF8.GetString(decryptBytes).Replace("\0", ""); //将字符串后尾的'\0'去掉
  283. }
  284. catch { }
  285. return str;
  286. }
  287. #endregion
  288. }
  289. }