기존 코드 침입을 최소화하면서 클라이언트와 서비스 서버 간의 데이터 교환을 효과적으로 달성하는 방법 암호화는 어떻습니까? ?
public class ApiTestController : ApiController { // GET api/<controller>/5 public object Get(int id) { return "value" + id; } }
ApiTestController
암호화된 요청 없음
GET /api/apitest?id=10
결과 반환
응답 "value10"
우리는 효과를 원합니다 달성한 목표는 다음과 같습니다:
Get /api/apitest?aWQ9MTA=
InZhbHVlMTAi 응답(복호화 결과 "value10")
또는 더보기기타암호화 방법
2. 기능 분석
기존 코드를 수정하지 않으려면 모두 알고 있습니다. api 컨트롤러는 라우터가 결정된 후에 초기화되므로 라우터 전에 GET 매개변수와 POST 매개변수를 암호화해야 합니다.
webapi Life Cycle 아래 그림을 보세요:
라우팅라우팅
전에 메시지 처리를 위한 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); }
3. 연습:
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 }
MessageEncryptionVersion1_0
암호화 및 복호화 버전 1.1 작성
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 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 try17 {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 catch29 {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 try42 {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 catch54 {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 }
EncrypExtends
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 // 同 body38 // 读取请求 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 }
JoyMessageHandler
最后在 webapiconfig 中将我们的消息处理添加到容器中
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 }
WebApiConfig
编写单元测试:
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 }
ApiTestControllerTests
至此为止功能实现完毕..
四.思想延伸
要想更加安全的方案,可以将给每位用户生成不同的 private key , 利用AES加密解密
위 내용은 WebApi는 통신 암호화를 구현합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!