using System; using System.Web; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using System.Threading.Tasks; using SDKCSharp.Common; using SDKCSharp.Request; using SDKCSharp.Response; using SDKCSharp.Utility; using System.IO; using Newtonsoft.Json.Linq; namespace SDKCSharp.Client { /// /// 客户端,申明一个即可 /// public class OpenClient { /// /// 默认配置 /// private static OpenConfig DEFAULT_CONFIG = new OpenConfig(); private Dictionary header = new Dictionary(); /// /// 接口请求url /// private string url; /// /// 平台提供的appId /// private string appId; /// /// 开放平台提供的私钥 /// private string privateKey; /// /// 开放平台提供的公钥 /// private string publicKeyPlatform; /// /// 配置项 /// private OpenConfig openConfig; /// /// 请求对象 /// private OpenRequest openRequest; /// /// 节点处理 /// private DataNameBuilder dataNameBuilder; /// /// 构建请求客户端 /// /// 接口url /// 平台分配的appId /// 平台分配的私钥 public OpenClient(string url, string appId, string privateKey) : this(url, appId, privateKey,false, DEFAULT_CONFIG) { } /// /// 构建请求客户端 /// /// 接口url /// 平台分配的appId /// 平台分配的私钥 /// 平台分配的公钥 public OpenClient(string url, string appId, string privateKey, string publicKeyPlatform) : this(url, appId, privateKey) { this.publicKeyPlatform = publicKeyPlatform; } /// /// 构建请求客户端 /// /// 接口url /// 平台分配的appId /// 平台分配的私钥 /// 如果设置 true 从文件中加载私钥 public OpenClient(string url, string appId, string privateKey, bool priKeyFromFile) : this(url, appId, privateKey, priKeyFromFile, DEFAULT_CONFIG) { } /// /// 构建请求客户端 /// /// 接口url /// 平台分配的appId /// 平台分配的私钥 /// 如果设置 true 从文件中加载私钥 /// 平台分配的公钥 public OpenClient(string url, string appId, string privateKey, bool priKeyFromFile, string publicKeyPlatform) : this(url, appId, privateKey, priKeyFromFile) { this.publicKeyPlatform = publicKeyPlatform; } /// /// 构建请求客户端 /// /// 接口url /// 平台分配的appId /// 平台分配的私钥 /// 如果设置 true 从文件中加载私钥 /// 配置项 public OpenClient(string url, string appId, string privateKey,bool priKeyFromFile, OpenConfig openConfig) { this.url = url; this.appId = appId; this.privateKey = privateKey; this.openConfig = openConfig; this.openRequest = new OpenRequest(openConfig); // 如果是从文件中加载私钥 if (priKeyFromFile) { this.privateKey = LoadCertificateFile(privateKey); } this.dataNameBuilder = openConfig.DataNameBuilder; } /// /// 构建请求客户端 /// /// 接口url /// 平台分配的appId /// 平台分配的私钥 /// 如果设置 true 从文件中加载私钥 /// 平台分配的公钥 /// 配置项 public OpenClient(string url, string appId, string privateKey, bool priKeyFromFile, string publicKeyPlatform, OpenConfig openConfig) : this(url, appId, privateKey, priKeyFromFile, openConfig) { this.publicKeyPlatform = publicKeyPlatform; } /// /// 加载秘钥文件 /// /// 返回私钥内容. /// 文件路径. private static string LoadCertificateFile(string filename) { if(!File.Exists(filename)) { throw new SopException("文件不存在," + filename); } using (FileStream fs = File.OpenRead(filename)) { byte[] data = new byte[fs.Length]; fs.Read(data, 0, data.Length); return Encoding.UTF8.GetString(data); } } /// /// 发送请求 /// /// 返回的Response类 /// 请求对象 /// 返回Response类 public virtual T Execute(BaseRequest request) where T : BaseResponse { return this.Execute(request, null); } /// /// 发送请求 /// /// 返回的Response类 /// 请求对象 /// accessToken /// 返回Response类 public virtual T Execute(BaseRequest request, string accessToken) where T : BaseResponse { RequestForm requestForm = request.CreateRequestForm(this.openConfig); Dictionary form = requestForm.Form; if (!string.IsNullOrEmpty(accessToken)) { form[this.openConfig.AccessTokenName] = accessToken; } form[this.openConfig.AppKeyName] = this.appId; string sign = SignUtil.CreateSign(form, privateKey, openConfig.Charset, openConfig.SignType); form[this.openConfig.SignName] = sign; string resp = this.DoExecute(url, requestForm, header); return this.ParseResponse(resp, request); } /// /// 执行请求 /// /// 请求url /// 请求内容 /// 请求header /// 返回服务器响应内容 protected virtual string DoExecute(string url, RequestForm requestForm, Dictionary header) { return openRequest.Request(this.url, requestForm, header); } /// /// 解析返回结果 /// /// 返回的Response /// 服务器响应内容 /// 请求Request /// 返回Response protected virtual T ParseResponse(string resp, BaseRequest request) where T: BaseResponse { string method = request.Method; string rootNodeName = this.dataNameBuilder.Build(method); string errorRootNode = openConfig.ErrorResponseName; Dictionary responseData = JsonUtil.ParseToDictionary(resp); bool errorResponse = responseData.ContainsKey(errorRootNode); if (errorResponse) { rootNodeName = errorRootNode; } object data = responseData[rootNodeName]; responseData.TryGetValue(openConfig.SignName, out object sign); if (sign != null && !string.IsNullOrEmpty(publicKeyPlatform)) { string signContent = BuildBizJson(rootNodeName, resp); if (!CheckResponseSign(signContent, sign.ToString(), publicKeyPlatform)) { ErrorResponse checkSignErrorResponse = SopSdkErrors.CHECK_RESPONSE_SIGN_ERROR; data = JsonUtil.ToJSONString(checkSignErrorResponse); } } string jsonData = data == null ? "{}" : data.ToString(); T t = JsonUtil.ParseObject(jsonData); t.Body = jsonData; return t; } /// /// 验证服务端返回的sign /// /// true, if response sign was checked, false otherwise. /// Response data. /// sign data. /// Public key platform. protected virtual bool CheckResponseSign(string signContent, string sign, string publicKeyPlatform) { try { Encoding charset = openConfig.Charset; SignType signType = openConfig.SignType; return SignUtil.RsaCheck(signContent, sign, publicKeyPlatform, charset, signType); } catch (Exception) { return false; } } /// /// 构建业务json内容。 /// 假设返回的结果是:{"alipay_story_get_response":{"msg":"Success","code":"10000","name":"海底小纵队","id":1},"sign":"xxx"} /// 将解析得到:{"msg":"Success","code":"10000","name":"海底小纵队","id":1} /// /// The biz json. /// 根节点名称. /// 返回内容. protected virtual string BuildBizJson(string rootNodeName, string body) { int indexOfRootNode = body.IndexOf(rootNodeName); if (indexOfRootNode < 0) { rootNodeName = openConfig.ErrorResponseName; indexOfRootNode = body.IndexOf(rootNodeName); } string result = null; if (indexOfRootNode > 0) { result = BuildJsonNodeData(body, rootNodeName, indexOfRootNode); } return result; } /// /// 获取业务结果,如下结果:{"alipay_story_get_response":{"msg":"Success","code":"10000","name":"海底小纵队","id":1},"sign":"xxx"} /// 将返回:{"msg":"Success","code":"10000","name":"海底小纵队","id":1} /// /// The json node data. /// Body. /// Root node. /// Index of root node. protected virtual string BuildJsonNodeData(string body, string rootNode, int indexOfRootNode) { int signDataStartIndex = indexOfRootNode + rootNode.Length + 2; int indexOfSign = body.IndexOf("\"" + openConfig.SignName + "\""); if (indexOfSign < 0) { return null; } int signDataEndIndex = indexOfSign - 1; int length = signDataEndIndex - signDataStartIndex; return body.Substring(signDataStartIndex, length); } } }