WebApi实现通讯加密
2018-06-22 07:45:42来源:未知 阅读 ()
一. 场景介绍:
如题如何有效的,最少量的现有代码侵入从而实现客户端与服务器之间的数据交换加密呢?
二. 探究:
1.需求分析
webapi服务端 有如下接口:
public class ApiTestController : ApiController { // GET api/<controller>/5 public object Get(int id) { return "value" + id; } }
无加密请求
GET /api/apitest?id=10
2.功能分析
// // 摘要: // A base type for handlers which only do some small processing of request and/or // response messages. public abstract class MessageProcessingHandler : DelegatingHandler { // // 摘要: // Creates an instance of a System.Net.Http.MessageProcessingHandler class. protected MessageProcessingHandler(); // // 摘要: // Creates an instance of a System.Net.Http.MessageProcessingHandler class with // a specific inner handler. // // 参数: // innerHandler: // The inner handler which is responsible for processing the HTTP response messages. protected MessageProcessingHandler(HttpMessageHandler innerHandler); // // 摘要: // Performs processing on each request sent to the server. // // 参数: // request: // The HTTP request message to process. // // cancellationToken: // A cancellation token that can be used by other objects or threads to receive // notice of cancellation. // // 返回结果: // Returns System.Net.Http.HttpRequestMessage.The HTTP request message that was // processed. protected abstract HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken); // // 摘要: // Perform processing on each response from the server. // // 参数: // response: // The HTTP response message to process. // // cancellationToken: // A cancellation token that can be used by other objects or threads to receive // notice of cancellation. // // 返回结果: // Returns System.Net.Http.HttpResponseMessage.The HTTP response message that was // processed. protected abstract HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken); // // 摘要: // Sends an HTTP request to the inner handler to send to the server as an asynchronous // operation. // // 参数: // request: // The HTTP request message to send to the server. // // cancellationToken: // A cancellation token that can be used by other objects or threads to receive // notice of cancellation. // // 返回结果: // Returns System.Threading.Tasks.Task`1.The task object representing the asynchronous // operation. // // 异常: // T:System.ArgumentNullException: // The request was null. protected internal sealed override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken); }
三. 实践:
1 /// <summary> 2 /// 加密解密接口 3 /// </summary> 4 public interface IMessageEnCryption 5 { 6 /// <summary> 7 /// 加密 8 /// </summary> 9 /// <param name="content"></param> 10 /// <returns></returns> 11 string Encode(string content); 12 /// <summary> 13 /// 解密 14 /// </summary> 15 /// <param name="content"></param> 16 /// <returns></returns> 17 string Decode(string content); 18 }
编写版本1.0 base64加密解密
1 /// <summary> 2 /// 加解密 只做 base64 3 /// </summary> 4 public class MessageEncryptionVersion1_0 : IMessageEnCryption 5 { 6 public string Decode(string content) 7 { 8 return content?.DecryptBase64(); 9 } 10 11 public string Encode(string content) 12 { 13 return content.EncryptBase64(); 14 } 15 }
编写版本1.1 des加密解密
1 /// <summary> 2 /// 数据加解密 des 3 /// </summary> 4 public class MessageEncryptionVersion1_1 : IMessageEnCryption 5 { 6 public static readonly string KEY = "fHil/4]0"; 7 public string Decode(string content) 8 { 9 return content.DecryptDES(KEY); 10 } 11 12 public string Encode(string content) 13 { 14 return content.EncryptDES(KEY); 15 } 16 }
附上加密解密的基本的一个封装类
1 public static class EncrypExtends 2 { 3 4 //默认密钥向量 5 private static byte[] Keys = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; 6 internal static string Key = "*@&$(@#H"; 7 8 //// <summary> 9 /// DES加密字符串 10 /// </summary> 11 /// <param name="encryptString">待加密的字符串</param> 12 /// <param name="encryptKey">加密密钥,要求为8位</param> 13 /// <returns>加密成功返回加密后的字符串,失败返回源串</returns> 14 public static string EncryptDES(this string encryptString, string encryptKey) 15 { 16 try 17 { 18 byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8)); 19 byte[] rgbIV = Keys; 20 byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString); 21 DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider(); 22 MemoryStream mStream = new MemoryStream(); 23 CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write); 24 cStream.Write(inputByteArray, 0, inputByteArray.Length); 25 cStream.FlushFinalBlock(); 26 return Convert.ToBase64String(mStream.ToArray()); 27 } 28 catch 29 { 30 return encryptString; 31 } 32 } 33 //// <summary> 34 /// DES解密字符串 35 /// </summary> 36 /// <param name="decryptString">待解密的字符串</param> 37 /// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param> 38 /// <returns>解密成功返回解密后的字符串,失败返源串</returns> 39 public static string DecryptDES(this string decryptString, string key) 40 { 41 try 42 { 43 byte[] rgbKey = Encoding.UTF8.GetBytes(key.Substring(0, 8)); 44 byte[] rgbIV = Keys; 45 byte[] inputByteArray = Convert.FromBase64String(decryptString); 46 DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider(); 47 MemoryStream mStream = new MemoryStream(); 48 CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write); 49 cStream.Write(inputByteArray, 0, inputByteArray.Length); 50 cStream.FlushFinalBlock(); 51 return Encoding.UTF8.GetString(mStream.ToArray()); 52 } 53 catch 54 { 55 return decryptString; 56 } 57 } 58 public static string EncryptBase64(this string encryptString) 59 { 60 return Convert.ToBase64String(Encoding.UTF8.GetBytes(encryptString)); 61 } 62 public static string DecryptBase64(this string encryptString) 63 { 64 return Encoding.UTF8.GetString(Convert.FromBase64String(encryptString)); 65 } 66 public static string DecodeUrl(this string cryptString) 67 { 68 return System.Web.HttpUtility.UrlDecode(cryptString); 69 } 70 public static string EncodeUrl(this string cryptString) 71 { 72 return System.Web.HttpUtility.UrlEncode(cryptString); 73 } 74 }
OK! 到此我们前题工作已经完成了80%,开始进行HTTP请求的 消息进和出的加密解密功能的实现.
我们暂时将加密的版本信息定义为 HTTP header头中 以 api_version 的value 来判别分别是用何种方式加密解密
header例:
api_version: 1.0
api_version: 1.1
1 /// <summary> 2 /// API消息请求处理 3 /// </summary> 4 public class JoyMessageHandler : MessageProcessingHandler 5 { 6 7 /// <summary> 8 /// 接收到request时 处理 9 /// </summary> 10 /// <param name="request"></param> 11 /// <param name="cancellationToken"></param> 12 /// <returns></returns> 13 protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken) 14 { 15 if (request.Content.IsMimeMultipartContent()) 16 return request; 17 // 获取请求头中 api_version版本号 18 var ver = System.Web.HttpContext.Current.Request.Headers.GetValues("api_version")?.FirstOrDefault(); 19 // 根据api_version版本号获取加密对象, 如果为null 则不需要加密 20 var encrypt = MessageEncryptionCreator.GetInstance(ver); 21 22 if (encrypt != null) 23 { 24 // 读取请求body中的数据 25 string baseContent = request.Content.ReadAsStringAsync().Result; 26 // 获取加密的信息 27 // 兼容 body: 加密数据 和 body: code=加密数据 28 baseContent = baseContent.Match("(code=)*(?<code>[\\S]+)", 2); 29 // URL解码数据 30 baseContent = baseContent.DecodeUrl(); 31 // 用加密对象解密数据 32 baseContent = encrypt.Decode(baseContent); 33 34 string baseQuery = string.Empty; 35 if (!request.RequestUri.Query.IsNullOrEmpty()) 36 { 37 // 同 body 38 // 读取请求 url query数据 39 baseQuery = request.RequestUri.Query.Substring(1); 40 baseQuery = baseQuery.Match("(code=)*(?<code>[\\S]+)", 2); 41 baseQuery = baseQuery.DecodeUrl(); 42 baseQuery = encrypt.Decode(baseQuery); 43 } 44 // 将解密后的 URL 重置URL请求 45 request.RequestUri = new Uri($"{request.RequestUri.AbsoluteUri.Split('?')[0]}?{baseQuery}"); 46 // 将解密后的BODY数据 重置 47 request.Content = new StringContent(baseContent); 48 } 49 50 return request; 51 } 52 53 /// <summary> 54 /// 处理将要向客户端response时 55 /// </summary> 56 /// <param name="response"></param> 57 /// <param name="cancellationToken"></param> 58 /// <returns></returns> 59 protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken) 60 { 61 //var isMediaType = response.Content.Headers.ContentType.MediaType.Equals(mediaTypeName, StringComparison.OrdinalIgnoreCase); 62 var ver = System.Web.HttpContext.Current.Request.Headers.GetValues("api_version")?.FirstOrDefault(); 63 var encrypt = MessageEncryptionCreator.GetInstance(ver); 64 if (encrypt != null) 65 { 66 if (response.StatusCode == HttpStatusCode.OK) 67 { 68 var result = response.Content.ReadAsStringAsync().Result; 69 // 返回消息 进行加密 70 var encodeResult = encrypt.Encode(result); 71 response.Content = new StringContent(encodeResult); 72 } 73 } 74 75 return response; 76 } 77 78 }
1 public static class WebApiConfig 2 { 3 public static void Register(HttpConfiguration config) 4 { 5 // Web API 配置和服务 6 // 将 Web API 配置为仅使用不记名令牌身份验证。 7 config.SuppressDefaultHostAuthentication(); 8 config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); 9 10 // Web API 路由 11 config.MapHttpAttributeRoutes(); 12 13 config.Routes.MapHttpRoute( 14 name: "DefaultApi", 15 routeTemplate: "api/{controller}/{id}", 16 defaults: new { id = RouteParameter.Optional } 17 ); 18 19 // 添加自定义消息处理 20 config.MessageHandlers.Add(new JoyMessageHandler()); 21 22 } 23 }
1 [TestMethod()] 2 public void GetTest() 3 { 4 var id = 10; 5 var resultSuccess = $"\"value{id}\""; 6 //不加密 7 Trace.WriteLine($"without encryption."); 8 var url = $"api/ApiTest?id={id}"; 9 Trace.WriteLine($"get url : {url}"); 10 var response = http.GetAsync(url).Result; 11 var result = response.Content.ReadAsStringAsync().Result; 12 Assert.AreEqual(result, resultSuccess); 13 Trace.WriteLine($"result : {result}"); 14 15 //使用 方案1加密 16 Trace.WriteLine($"encryption case one."); 17 18 url = $"api/ApiTest?code=" + $"id={id}".EncryptBase64().EncodeUrl(); 19 20 Trace.WriteLine($"get url : {url}"); 21 22 http.DefaultRequestHeaders.Clear(); 23 http.DefaultRequestHeaders.Add("api_version", "1.0"); 24 response = http.GetAsync(url).Result; 25 26 result = response.Content.ReadAsStringAsync().Result; 27 28 Trace.WriteLine($"result : {result}"); 29 30 result = result.DecryptBase64(); 31 32 Trace.WriteLine($"DecryptBase64 : {result}"); 33 34 Assert.AreEqual(result, resultSuccess); 35 36 //使用 方案2 加密通讯 37 Trace.WriteLine($"encryption case one."); 38 39 url = $"api/ApiTest?code=" + $"id={id}".EncryptDES(MessageEncryptionVersion1_1.KEY).EncodeUrl(); 40 41 Trace.WriteLine($"get url : {url}"); 42 43 http.DefaultRequestHeaders.Clear(); 44 http.DefaultRequestHeaders.Add("api_version", "1.1"); 45 response = http.GetAsync(url).Result; 46 47 result = response.Content.ReadAsStringAsync().Result; 48 49 Trace.WriteLine($"result : {result}"); 50 51 result = result.DecryptDES(MessageEncryptionVersion1_1.KEY); 52 53 Trace.WriteLine($"DecryptBase64 : {result}"); 54 55 Assert.AreEqual(result, resultSuccess); 56 }
四.思想延伸
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- asp.net源程序编译为dll文件并调用的实现过程 2020-03-29
- WPF实现带全选复选框的列表控件 2020-03-29
- PHP session实现购物车功能 2020-03-23
- WPF实现简单的跑马灯效果 2020-03-23
- ASP.NET使用AjaxPro实现前端跟后台交互详解 2020-03-19
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash