WebApi实现通讯加密 (转)
http://www.cnblogs.com/jonneydong/p/WebApi_Encryption.html
一. 场景介绍:
如题如何有效的,最少量的现有代码侵入从而实现客户端与服务器之间的数据交换加密呢?
二. 探究:
1.需求分析
webapi服务端 有如下接口:

public class ApiTestController : ApiController
{ // GET api/<controller>/5
public object Get(int id)
{
return "value" + id;
}
}

ApiTestController
无加密请求
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);
}

MessageProcessingHandler
三. 实践:

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 }

IMessageEnCryption
编写版本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 }

MessageEncryptionVersion1_0
编写版本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 }

MessageEncryptionVersion1_1
附上加密解密的基本的一个封装类

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 }

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 // 同 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 }

JoyMessageHandler

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
四.思想延伸
WebApi实现通讯加密 (转)的更多相关文章
- WebApi实现通讯加密
一. 场景介绍: 如题如何有效的,最少量的现有代码侵入从而实现客户端与服务器之间的数据交换加密呢? 二. 探究: 1.需求分析 webapi服务端 有如下接口: public class ApiTes ...
- WebApi服务Uri加密及验证的两种方式
最近的一个项目要求服务端与UI层分离,业务层以WebApi方式向外提供所有业务服务,服务在数据保密性方面提出了要求,主要包括: 1:客户端认证: 2:服务请求超时(默认5分钟): 3:服务Get请求的 ...
- ECC(Ellipse Curve Cryptography)+AES(Advanced Encryption Standard)前端通讯加密模拟(使用eccrypto-js)
前置知识 不了解对称加密与非对称加密的小伙伴可以看看下面的文章,想详细学习与区块链有关的加密算法可以戳这里 对称与非对称加密 https://blog.csdn.net/u013320868/arti ...
- Self Host WebApi服务传输层SSL加密(服务器端+客户端调用)
接上篇<WebApi服务URI加密及验证的两种方式>,在实际开发中,仅对URI进行加密是不够的,在传输层采用SSL加密也是必须的. 如果服务寄宿于IIS,那对传输层加密非常简单仅需要配置一 ...
- SQLite学习笔记(十)&&加密
随着移动互联网的发展,手机使用越来越广泛,sqlite作为手机端存储的一种解决方案,使用也非常普遍.但是sqlite本身安全特性却比较弱,比如不支持用户权限,只要能获取到数据库文件就能进行访问:另外也 ...
- .NET中的DES对称加密
DES是一种对称加密(Data Encryption Standard)算法,于1977年得到美国政府的正式许可,是一种用56位密钥来加密64位数据的方法.一般密码长度为8个字节,其中56位加密密钥, ...
- SQLite XXTea加密学习
这几天优化数据库读写,移植了xxtea加密到最新的数据库sqlite 3.12.2里,一些好文章放在这里.移植后,数据库读写性能异常优秀! 这几天又发现,数据库还是发生了无法写入情况,数据库崩溃掉了. ...
- 单片机上使用TEA加密通信(转)
源:单片机上使用TEA加密通信 本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环境: 主机:WIN7 开发环境:MDK4.72 单片机:STM32 说 ...
- Nginx集群之SSL证书的WebApi微服务
目录 1 大概思路... 1 2 Nginx集群之SSL证书的WebApi微服务... 1 3 HTTP与HTTPS(SSL协议)... 1 4 Ope ...
随机推荐
- linux usb驱动记录(一)
一.linux 下的usb驱动框架 在linux系统中,usb驱动可以从两个角度去观察,一个是主机侧,一个是设备侧.linux usb 驱动的总体框架如下图所示: 从主机侧看usb驱动可分为四层: ...
- 构建之法个人作业5——alpha2项目测试
[相关信息] Q A 这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/2019autumnsystemanalysisanddesign/ 这个作业要求在 ...
- 原生js中如果有多个onload事件解决方案
在一个页面中有两个JavaScript 分别都用到了window.onload 一个是:window.onload=func1,另一个是:window.onload=func2 这样就造成了一个Jav ...
- centos6 mini安装图形界面,并vnc远程控制
1.安装图形界面sudo yum groupinstall basic-desktop desktop-platform x11 fonts 2.安装vnc服务sudo yum -y install ...
- java双指针的简单理解
一.什么是双指针 双指针我所理解地是在遍历对象时,不是使用单个指针进行访问,而是使用两个相同方向或者相反方向的指针进行遍历,从而达到相应的目的. 在JAVA中并没有像C/C++指针地概念,所以这里所说 ...
- Mybatis那些事-拦截器(Plugin+Interceptor)
作者:yhjyumi的专栏 数据权限实现(Mybatis拦截器+JSqlParser) Mybatis的拦截器实现机制,使用的是JDK的InvocationHandler. 当我们调用Paramete ...
- BZOJ 2244: [SDOI2011]拦截导弹 (CDQ分治 三维偏序 DP)
题意 略- 分析 就是求最长不上升子序列,坐标取一下反就是求最长不下降子序列,比较大小是二维(h,v)(h,v)(h,v)的比较.我们不看概率,先看第一问怎么求最长不降子序列.设f[i]f[i]f[i ...
- [转]vue解决刷新页面vuex数据、params参数消失的问题
一般项目都会有一些逻辑需要传递值给另一个页面,那么有的时候就会出现一个问题:用户刷新了页面,诶?数据没了,参数错误.那么今天经过总结,解决了这个问题.我在最新的项目中,通过了一下几种情况进行传值: 1 ...
- Java数据库小项目01--实现用户登录注册
先实现数据库和数据表,检测正常后再做其他的 CREATE TABLE users( username ) NOT NULL, PASSWORD ) NOT NULL); INSERT INTO use ...
- nextUntil([exp|ele][,fil]) 查找当前元素之后所有的同辈元素,直到遇到匹配的那个元素为止。
nextUntil([exp|ele][,fil]) 概述 查找当前元素之后所有的同辈元素,直到遇到匹配的那个元素为止. 如果提供的jQuery代表了一组DOM元素,.nextUntil()方法也能让 ...