您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關使用WebApi怎么實現一個通訊加密功能,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
1.需求分析
webapi服務端 有如下接口:
public class ApiTestController : ApiController { // GET api/<controller>/5 public object Get(int id) { return "value" + id; } } ApiTestController
無加密請求
GET /api/apitest?id=10
返回結果
response "value10"
我們想要達到的效果為:
Get /api/apitest?aWQ9MTA=
response InZhbHVlMTAi (解密所得 "value10")
或者更多其它方式加密
2.功能分析
要想對現有代碼不做任何修改, 我們都知道所有api controller 初始化在router確定之后, 因此我們應在router之前將GET參數和POST的參數進行加密才行.
看下圖 webapi 生命周期:
我們看到在 路由routing 之前 有DelegationgHander 層進行消息處理.
因為我們要對每個請求進行參數解密處理,并且又將返回消息進行加密處理, 因此我們 瞄準 MessageProcessingHandler
// // 摘要: // 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); } MessageProcessingHandler
三. 實踐:
現在我們將來 先實現2個版本的通訊加密解密功能,定為 版本1.0 base64加密, 版本1.1 Des加密
/// <summary> /// 加密解密接口 /// </summary> public interface IMessageEnCryption { /// <summary> /// 加密 /// </summary> /// <param name="content"></param> /// <returns></returns> string Encode(string content); /// <summary> /// 解密 /// </summary> /// <param name="content"></param> /// <returns></returns> string Decode(string content); } IMessageEnCryption
編寫版本1.0 base64加密解密
/// <summary> /// 加解密 只做 base64 /// </summary> public class MessageEncryptionVersion1_0 : IMessageEnCryption { public string Decode(string content) { return content?.DecryptBase64(); } public string Encode(string content) { return content.EncryptBase64(); } } MessageEncryptionVersion1_0
編寫版本1.1 des加密解密
/// <summary> /// 數據加解密 des /// </summary> public class MessageEncryptionVersion1_1 : IMessageEnCryption { public static readonly string KEY = "fHil/4]0"; public string Decode(string content) { return content.DecryptDES(KEY); } public string Encode(string content) { return content.EncryptDES(KEY); } } MessageEncryptionVersion1_1
附上加密解密的基本的一個封裝類
public static class EncrypExtends { //默認密鑰向量 private static byte[] Keys = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; internal static string Key = "*@&$(@#H"; //// <summary> /// DES加密字符串 /// </summary> /// <param name="encryptString">待加密的字符串</param> /// <param name="encryptKey">加密密鑰,要求為8位</param> /// <returns>加密成功返回加密后的字符串,失敗返回源串</returns> public static string EncryptDES(this string encryptString, string encryptKey) { try { byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8)); byte[] rgbIV = Keys; byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString); DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider(); MemoryStream mStream = new MemoryStream(); CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write); cStream.Write(inputByteArray, 0, inputByteArray.Length); cStream.FlushFinalBlock(); return Convert.ToBase64String(mStream.ToArray()); } catch { return encryptString; } } //// <summary> /// DES解密字符串 /// </summary> /// <param name="decryptString">待解密的字符串</param> /// <param name="decryptKey">解密密鑰,要求為8位,和加密密鑰相同</param> /// <returns>解密成功返回解密后的字符串,失敗返源串</returns> public static string DecryptDES(this string decryptString, string key) { try { byte[] rgbKey = Encoding.UTF8.GetBytes(key.Substring(0, 8)); byte[] rgbIV = Keys; byte[] inputByteArray = Convert.FromBase64String(decryptString); DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider(); MemoryStream mStream = new MemoryStream(); CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write); cStream.Write(inputByteArray, 0, inputByteArray.Length); cStream.FlushFinalBlock(); return Encoding.UTF8.GetString(mStream.ToArray()); } catch { return decryptString; } } public static string EncryptBase64(this string encryptString) { return Convert.ToBase64String(Encoding.UTF8.GetBytes(encryptString)); } public static string DecryptBase64(this string encryptString) { return Encoding.UTF8.GetString(Convert.FromBase64String(encryptString)); } public static string DecodeUrl(this string cryptString) { return System.Web.HttpUtility.UrlDecode(cryptString); } public static string EncodeUrl(this string cryptString) { return System.Web.HttpUtility.UrlEncode(cryptString); } } EncrypExtends
OK! 到此我們前題工作已經完成了80%,開始進行HTTP請求的 消息進和出的加密解密功能的實現.
我們暫時將加密的版本信息定義為 HTTP header頭中 以 api_version 的value 來判別分別是用何種方式加密解密
header例:
api_version: 1.0
api_version: 1.1
/// <summary> /// API消息請求處理 /// </summary> public class JoyMessageHandler : MessageProcessingHandler { /// <summary> /// 接收到request時 處理 /// </summary> /// <param name="request"></param> /// <param name="cancellationToken"></param> /// <returns></returns> protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken) { if (request.Content.IsMimeMultipartContent()) return request; // 獲取請求頭中 api_version版本號 var ver = System.Web.HttpContext.Current.Request.Headers.GetValues("api_version")?.FirstOrDefault(); // 根據api_version版本號獲取加密對象, 如果為null 則不需要加密 var encrypt = MessageEncryptionCreator.GetInstance(ver); if (encrypt != null) { // 讀取請求body中的數據 string baseContent = request.Content.ReadAsStringAsync().Result; // 獲取加密的信息 // 兼容 body: 加密數據 和 body: code=加密數據 baseContent = baseContent.Match("(code=)*(?<code>[\\S]+)", 2); // URL解碼數據 baseContent = baseContent.DecodeUrl(); // 用加密對象解密數據 baseContent = encrypt.Decode(baseContent); string baseQuery = string.Empty; if (!request.RequestUri.Query.IsNullOrEmpty()) { // 同 body // 讀取請求 url query數據 baseQuery = request.RequestUri.Query.Substring(1); baseQuery = baseQuery.Match("(code=)*(?<code>[\\S]+)", 2); baseQuery = baseQuery.DecodeUrl(); baseQuery = encrypt.Decode(baseQuery); } // 將解密后的 URL 重置URL請求 request.RequestUri = new Uri($"{request.RequestUri.AbsoluteUri.Split('?')[0]}?{baseQuery}"); // 將解密后的BODY數據 重置 request.Content = new StringContent(baseContent); } return request; } /// <summary> /// 處理將要向客戶端response時 /// </summary> /// <param name="response"></param> /// <param name="cancellationToken"></param> /// <returns></returns> protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken) { //var isMediaType = response.Content.Headers.ContentType.MediaType.Equals(mediaTypeName, StringComparison.OrdinalIgnoreCase); var ver = System.Web.HttpContext.Current.Request.Headers.GetValues("api_version")?.FirstOrDefault(); var encrypt = MessageEncryptionCreator.GetInstance(ver); if (encrypt != null) { if (response.StatusCode == HttpStatusCode.OK) { var result = response.Content.ReadAsStringAsync().Result; // 返回消息 進行加密 var encodeResult = encrypt.Encode(result); response.Content = new StringContent(encodeResult); } } return response; } } JoyMessageHandler
最后在 webapiconfig 中將我們的消息處理添加到容器中
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服務 // 將 Web API 配置為僅使用不記名令牌身份驗證。 config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); // 添加自定義消息處理 config.MessageHandlers.Add(new JoyMessageHandler()); } } WebApiConfig
編寫單元測試:
[TestMethod()] public void GetTest() { var id = 10; var resultSuccess = $"\"value{id}\""; //不加密 Trace.WriteLine($"without encryption."); var url = $"api/ApiTest?id={id}"; Trace.WriteLine($"get url : {url}"); var response = http.GetAsync(url).Result; var result = response.Content.ReadAsStringAsync().Result; Assert.AreEqual(result, resultSuccess); Trace.WriteLine($"result : {result}"); //使用 方案1加密 Trace.WriteLine($"encryption case one."); url = $"api/ApiTest?code=" + $"id={id}".EncryptBase64().EncodeUrl(); Trace.WriteLine($"get url : {url}"); http.DefaultRequestHeaders.Clear(); http.DefaultRequestHeaders.Add("api_version", "1.0"); response = http.GetAsync(url).Result; result = response.Content.ReadAsStringAsync().Result; Trace.WriteLine($"result : {result}"); result = result.DecryptBase64(); Trace.WriteLine($"DecryptBase64 : {result}"); Assert.AreEqual(result, resultSuccess); //使用 方案2 加密通訊 Trace.WriteLine($"encryption case one."); url = $"api/ApiTest?code=" + $"id={id}".EncryptDES(MessageEncryptionVersion1_1.KEY).EncodeUrl(); Trace.WriteLine($"get url : {url}"); http.DefaultRequestHeaders.Clear(); http.DefaultRequestHeaders.Add("api_version", "1.1"); response = http.GetAsync(url).Result; result = response.Content.ReadAsStringAsync().Result; Trace.WriteLine($"result : {result}"); result = result.DecryptDES(MessageEncryptionVersion1_1.KEY); Trace.WriteLine($"DecryptBase64 : {result}"); Assert.AreEqual(result, resultSuccess); } ApiTestControllerTests
看完上述內容,你們對使用WebApi怎么實現一個通訊加密功能有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。