using System; using System.Collections.Generic; using Top.Api.Util; using System.Threading; using Top.Api.Report; namespace Top.Api.Security { /// /// 加、解密核心类 /// public class SecurityCore : SecurityConstants { private static readonly ITopLogger Log = Top.Api.Log.Instance; // 缓存用户单独分配秘钥,需要加同步锁 private static readonly IDictionary AppUserSecretCache = new Dictionary(); private static readonly IDictionary AppSecretCache = new Dictionary(); private static readonly object EmptyObject = new object(); private static readonly object CacheLock = new object(); private static readonly object AppLock = new object(); private static readonly object AsynQueueKeyLock = new object(); private string randomNum;// 伪随机码 private DefaultTopClient topClient; private static IDictionary asynQueueKey = new Dictionary(); private static readonly IDictionary> AllAppConfig = new Dictionary>(); private bool streetest; public static IDictionary GetAppUserSecretCache() { return AppUserSecretCache; } /// /// 判断密文是否支持检索 /// /// /// /// public bool IsIndexEncrypt(string key, Nullable version) { if (version != null && version < 0) { key = PREVIOUS + key; } else { key = CURRENT + key; } IDictionary appConfig = getAppConfig(); if (appConfig == null) { return false; } object encryptType = null; appConfig.TryGetValue(key, out encryptType); return INDEX_ENCRYPT_TYPE.Equals(encryptType); } private IDictionary getAppConfig() { IDictionary appConfig = null; AllAppConfig.TryGetValue(topClient.appKey, out appConfig); return appConfig; } /// /// 获取压缩长度 /// /// public int GetCompressLen() { IDictionary appConfig = getAppConfig(); if (appConfig != null) { object compressLen = null; appConfig.TryGetValue(ENCRYPT_INDEX_COMPRESS_LEN, out compressLen); if (compressLen != null) { return Convert.ToInt32(compressLen); } } return DEFAULT_INDEX_ENCRYPT_COMPRESS_LEN; } /// /// 获取滑动窗口大小 /// /// public int GetSlideSize() { IDictionary appConfig = getAppConfig(); if (appConfig != null) { object encryptSlideSize = null; appConfig.TryGetValue(ENCRYPT_SLIDE_SIZE, out encryptSlideSize); if (encryptSlideSize != null) { return Convert.ToInt32(encryptSlideSize); } } return DEFAULT_ENCRYPT_SLIDE_SIZE; } public SecurityCore(DefaultTopClient topClient, string randomNum, bool streetest) { this.streetest = streetest; this.topClient = topClient; this.randomNum = randomNum; // 初始化报表 ApiReporter apiReporter = new ApiReporter(); apiReporter.InitSecret(topClient); } public void SetRandomNum(string randomNum) { this.randomNum = randomNum; } /// /// 获取秘钥 /// /// /// /// public SecretContext GetSecret(string session, Nullable secretVersion) { SecretContext secretContext = GetSecret(session, GenerateSecretKey(session, secretVersion)); if (secretContext != null) { if (secretContext.IsValid()) { return secretContext; } if (secretContext.IsMaxValid()) { // 异步更新秘钥 AsynUpdateSecret(session, secretVersion); return secretContext; } string cacheKey = GenerateSecretKey(session, secretVersion); lock (CacheLock) { if (session != null) { AppUserSecretCache.Remove(cacheKey); } else { AppSecretCache.Remove(cacheKey); } } // 同步调用获取秘钥 return CallSecretApi(session, secretVersion); } else { // 同步调用获取秘钥 return CallSecretApi(session, secretVersion); } } private string GenerateSecretKey(string session, Nullable secretVersion) { if (session == null) { return this.topClient.appKey; } if (secretVersion == null) { return session; } return session + "_" + secretVersion; } /// /// 从本地获取秘钥信息 /// /// /// /// private SecretContext GetSecret(string session, string cacheKey) { SecretContext secretContext; if (session != null) { AppUserSecretCache.TryGetValue(cacheKey, out secretContext); } else { AppSecretCache.TryGetValue(cacheKey, out secretContext); } return secretContext; } /// /// 调用获取秘钥api /// /// /// /// private SecretContext CallSecretApi(string session, Nullable secretVersion) { // 获取伪随机码 if (string.IsNullOrEmpty(randomNum)) { throw new ArgumentException("randomNum can`t be empty"); } TopSecretGetRequest request = new TopSecretGetRequest(); request.RandomNum = randomNum; request.SecretVersion = secretVersion; if (streetest) { request.AddOtherParameter("tb_eagleeyex_t", "1"); } TopSecretGetResponse response; if (session != null && session.StartsWith(UNDERLINE)) { string customerUserId = session.Substring(1); if (!StringUtil.IsDigits(customerUserId)) { throw new ArgumentException("session invalid"); } request.CustomerUserId = Convert.ToInt64(customerUserId); response = topClient.Execute(request, null); } else { response = topClient.Execute(request, session); } if (!response.IsError) { IDictionary appConfig = null; if (!string.IsNullOrEmpty(response.AppConfig)) { appConfig = (IDictionary)TopUtils.JsonToObject(response.AppConfig); putAppConfig(appConfig); } SecretContext secretContext = new SecretContext(); if (response.Secret != null) { long currentTime = TopUtils.GetCurrentTimeMillis(); secretContext.InvalidTime = currentTime + (response.Interval * 1000); secretContext.MaxInvalidTime = (currentTime + (response.MaxInterval * 1000)); secretContext.Secret = Convert.FromBase64String(response.Secret); secretContext.SecretVersion = response.SecretVersion; } else { if (appConfig != null) { object publishStatus = null; appConfig.TryGetValue(PUBLISH_STATUS, out publishStatus); if (BETA_STATUS.Equals(publishStatus)) { // 设置空缓存 SetNullCache(secretContext); } } } PutToCache(session, secretVersion, secretContext); return secretContext; } else { // 查找不到历史秘钥 if ("20005".Equals(response.SubErrCode)) { SecretContext secretContext = new SecretContext(); // 设置空缓存 SetNullCache(secretContext); PutToCache(session, secretVersion, secretContext); return secretContext; } throw new SecretException(response.ErrCode, response.ErrMsg, response.SubErrCode, response.SubErrMsg); } } private void putAppConfig(IDictionary appConfig) { lock (AppLock) { if (!AllAppConfig.ContainsKey(topClient.appKey)) { AllAppConfig.Add(topClient.appKey, appConfig); } } } private void PutToCache(string session, Nullable secretVersion, SecretContext secretContext) { string cacheKey = GenerateSecretKey(session, secretVersion); lock (CacheLock) { if (session != null) { if (AppUserSecretCache.ContainsKey(cacheKey)) { AppUserSecretCache[cacheKey] = secretContext; } else { AppUserSecretCache.Add(cacheKey, secretContext); } } else { if (AppSecretCache.ContainsKey(cacheKey)) { AppSecretCache[cacheKey] = secretContext; } else { AppSecretCache.Add(cacheKey, secretContext); } } } } /// /// 设置空缓存 /// /// private void SetNullCache(SecretContext secretContext) { long currentTime = TopUtils.GetCurrentTimeMillis(); secretContext.InvalidTime = currentTime + (DEFAULT_INTERVAL * 1000); secretContext.MaxInvalidTime = currentTime + (DEFAULT_MAX_INTERVAL * 1000); } /// /// 异步更新秘钥 /// /// /// private void AsynUpdateSecret(string session, Nullable secretVersion) { string cacheKey = GenerateSecretKey(session, secretVersion); lock (AsynQueueKeyLock) { // 不需要重复提交秘钥请求 if (asynQueueKey.ContainsKey(cacheKey)) { return; } SecretContext secretContext = GetSecret(session, GenerateSecretKey(session, secretVersion)); if (secretContext != null && secretContext.IsValid()) { return; } asynQueueKey.Add(cacheKey, EmptyObject); } WaitCallback secretApiCallback = (state) => { try { CallSecretApi(session, secretVersion); } catch (Exception e) { Log.Error(string.Format("asyn update secret error: {0}", e.Message)); } finally { lock (AsynQueueKeyLock) { asynQueueKey.Remove(cacheKey); } } }; try { ThreadPool.QueueUserWorkItem(secretApiCallback); } catch (Exception e) { lock (AsynQueueKeyLock) { asynQueueKey.Remove(cacheKey); } Log.Error(string.Format("add QueueUserWorkItem error: {0}", e.Message)); } } } }