温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

使用WebApi怎么实现一个通讯加密功能

发布时间:2021-02-08 17:22:17 来源:亿速云 阅读:259 作者:Leah 栏目:开发技术

今天就跟大家聊聊有关使用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 生命周期:

使用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怎么实现一个通讯加密功能有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI