一。场景介绍:
如题如何有效的,最少量的现有代码侵入从而实现客户端与服务器之间的数据交换加密呢?
二。探究:
1.需求分析
webapi服务端有如下接口:
公共类APitestcontroller : APi控制器{//GET API/controller/5公共对象GET(int id){返回值' value ' id}}ApiTestController无加密请求
GET /api/apitest?id=10
返回结果
响应'值10 '
我们想要达到的效果为:
Get /api/apitest?aWQ9MTA=响应InZhbHVlMTAi(解密所得值10')
或者更多其它方式加密
2.功能分析
要想对现有代码不做任何修改,我们都知道所有美国石油学会(American Petroleum Institute)控制器初始化在路由器确定之后,因此我们应在路由器之前将得到参数和邮政的参数进行加密才行。
看下图webapi生命周期:
我们看到在路由选择途径之前有委托代理人层进行消息处理。
因为我们要对每个请求进行参数解密处理,并且又将返回消息进行加密处理,因此我们瞄准MessageProcessingHandler
////摘要: //只对请求和/或//响应消息进行少量处理的处理程序的基本类型。公共抽象类MessageProcessingHandler : DelegatingHandler {////摘要: //创建系统实例净。Http。消息处理处理程序类。受保护的MessageProcessingHandler();////摘要: //创建系统实例净。Http。消息处理处理程序类,带有//特定的内部处理程序。////参数: //innerHandler: //负责处理超文本传送协议响应消息的内部处理程序。受保护的MessageProcessingHandler(Httpmessagehandler内部处理程序);////摘要: //对发送到服务器的每个请求执行处理。////参数: //request: //要处理的超文本传送协议请求消息////cancelationtoken ://可由其他对象或线程用来接收//取消通知的取消令牌。////返回结果: //退货系统。被//处理的超文本传送协议(Hyper Text Transport Protocol的缩写)请求消息。受保护的抽象Httprequestmessage进程请求(Httprequestmessage请求,cancelatitoken cancelatitoken);////摘要: //对来自服务器的每个响应执行处理。////参数: //response: //要处理的超文本传送协议响应消息////cancelationtoken ://可由其他对象或线程用来接收//取消通知的取消令牌。////返回结果: //退货系统。被//处理的超文本传送协议(Hyper Text Transport Protocol的缩写)响应消息。受保护的抽象HttpResponseMessage进程响应(HttpResponseMessage响应cancelationtoken cancelationtoken);////摘要: //向内部处理程序发送一个超文本传送协议请求,作为异步//操作发送到服务器。////参数: //request: //要发送到服务器的超文本传送协议请求消息////cancelationtoken ://可由其他对象或线程用来接收//取消通知的取消令牌。////返回结果: //退货系统。线程。任务。任务` 1。表示异步//操作的任务对象。////异常://T3360 system .ArgumentNullException: //请求为空。受保护的内部密封覆盖tashttpresponsemessage发送异步(Httprequestmessage请求cancelationtoken cancelationtoken);}MessageProcessingHandler三。实践:
现在我们将来先实现2个版本的通讯加密解密功能,定为版本1.0 base64加密,版本1.1 Des加密
///摘要///加密解密接口////摘要公共接口IMessageEnCryption { ///摘要///加密////summary////param name=' content '/param////returns/returns string Encode(字符串内容);///摘要///解密////summary////param name=' content '/param////returns/returns string Decode(字符串内容);}IMessageEnCryption编写版本1.0 base64加密解密
///摘要///加解密只做base64/摘要公共类messageencryption version 1 _ 0 : IMessageEnCryption {公共字符串解码(字符串内容){返回内容?decryptbase64();}公共字符串编码(字符串内容){返回内容EncryptBase64();} }MessageEncryptionVersion1_0编写版本1.1 des加密解密
///摘要///数据加解密des////摘要公共类messageencryption version 1 _ 1 : IMessageEnCryption { public static readonly string KEY=' fHil/4]0 ';公共字符串解码(字符串内容){返回内容。解密器(密钥);}公共字符串编码(字符串内容){返回内容加密器(KEY);} }MessageEncryptionVersion1_1附上加密解密的基本的一个封装类
公共静态类加密扩展{ //默认密钥向量私有静态字节[]密钥={0x12、0x34、0x56、0x78、0x90、0xAB、0xCD、0Xef };内部静态字符串key=' * @ $(@ # H ';////摘要///DES加密字符串////summary////param name=' EncryptString '待加密的字符串/param ///param name='encryptKey '加密密钥,要求为8位/param /返回加密成功返回加密后的字符串,失败返回源串/返回公共静态字符串EncryptDES(此字符串encryptString,string EncryptKey){尝试{ byte[]rgbKey=加密.UTF8。获取字节(加密密钥.子串(0,8));byte[]rgbIV=Keys;字节[] inputByteArray=编码. UTF8。GetBytes(EncryptString);desryptoservice提供程序dCSP=new desryptoseservice提供程序();内存流Mstream=新内存流();加密流c流=新的加密流(mStream,dCSP .CreateEncryptor(rgbKey,rgbIV),CryptoStreamMode .写);cStream .Write(inputByteArray,0,inputByteArray .长度);cStream .flush fill block();返回转换.到base64字符串(MsStream .ToArray());} catch { return EncryptString } }////summary///DES解密字符串////summary////param name=' DecryptString '待解密的字符串/param ///param name='decryptKey '解密密钥,要求为8位,和加密密钥相同/param /返回解密成功返回解密后的字符串,失败返源串/返回公共静态字符串解密器(此字符串decryptString,string key){尝试{ byte[]rgbKey=Encoding .UTF8。GetBytes(键。子串(0,8));byte[]rgbIV=Keys;字节[]输入范围=转换.从base64字符串(DecryptString);解扰服务提供商DCSP=新的解扰服务提供商();内存流Mstream=新内存流();加密流=新加密流(DCSP,密钥流CreateDecryptor(rgbKey,rgbIV),CryptoStreamMode .写);cStream .Write(inputByteArray,0,inputByteArray .长度);cStream .flush fill block();返回编码. UTF8。GetString(MsStream .ToArray());} catch { return decryptString} }公共静态字符串EncryptBase64(此字符串为EncryptString){ 0返回转换.ToBase64String(编码. UTF8。GetBytes(EncryptString));}公共静态字符串DecryptBase64(此字符串为EncryptString){ 0返回加密.转换.来自base64字符串(EncryptString));}公共静态字符串DecodeUrl(此字符串为cryptString){ 0返回系统.网络。Httputity。网址解码(cryptString);}公共静态字符串EncodeUrl(此字符串cryptString){ 0返回系统.网络。Httputity。URL encode(cryptString);} }加密扩展确定!到此我们前题工作已经完成了80%,开始进行超文本传送协议请求的消息进和出的加密解密功能的实现。
我们暂时将加密的版本信息定义为超文本传送协议头头中以api _版本的价值来判别分别是用何种方式加密解密
页眉例:
api_version: 1.0
api_version: 1.1
///摘要///API消息请求处理////摘要公共类JoyMessageHandler : messageprocessing handler {///summary///接收到请求时处理////summary////param name=' request '/param///param name=' canceltintoken '/param///returns/returns受保护的重写Httprequestmessage进程请求(Httprequestmessage请求,cancel titon ken cancel titon ken){ if(request .内容。IsMimeMultipartContent())返回请求;//获取请求头中api _版本版本号系统网络。httpcontext。当前。请求。标题。getvalues(' API _ version ')?first ordefault();//根据api _版本版本号获取加密对象,如果为空则不需要加密var encrypt=MessageEncryptionCreator .GetInstance(ver);如果(加密!=null) { //读取请求身体中的数据字符串基本内容=请求内容。ReadAsStringAsync().结果;//获取加密的信息//兼容body:加密数据和body:代码=加密数据基本内容=基本内容。匹配('(代码=)*(?代码[\S])',2);//网址解码数据基本内容=基本内容DecodeUrl();//用加密对象解密数据基本内容=加密.解码(BaseContent);字符串基础查询=字符串.空的;if(!请求请求uri。查询。isnullorempty()){//同身体/读取请求全球资源定位器(Uniform Resource Locator)查询数据baseQuery=请求查询。子串(1);基本查询=基本查询.匹配('(代码=)*(?代码[\S])',2);基本查询=基本查询.DecodeUrl();baseQuery=加密。解码(Basequery);} //将解密后的统一资源定位器重置统一资源定位器请求请求RequestUri=新的Uri($'{request .RequestUri。绝对的。拆分('?')[0]}?{ Basequery } ');//将解密后的身体数据重置请求内容=新字符串内容(基本内容);}退货请求;} ///摘要///处理将要向客户端反应时////summary////param name=' response '/param///param name=' canceltintoken '/param///returns/returns受保护覆盖httpresponse消息处理响应(httpresponse消息响应,canceltintoken){//var is mediatype=response .内容。标题。内容类型。mediatype。equals(mediaTypeName,StringComparison .organiglagnorcase);系统网络。httpcontext。当前。请求。标题。getvalues(' API _ version ')?first ordefault();var encrypt=MessageEncryptionCreator .GetInstance(ver);如果(加密!=null) { if(响应StatusCode==HttpStatusCode .OK) { var结果=响应内容。ReadAsStringAsync().结果;//返回消息进行加密var encodeResult=encrypt .编码(结果);回应content=新字符串内容(encodereresult);} }返回响应;} }JoyMessageHandler最后在webapiconfig中将我们的消息处理添加到容器中
公共静态类WebApiConfig {公共静态void Register(HttpConfiguration config){//Web API配置和服务//将网络应用编程接口配置为仅使用不记名令牌身份验证配置suppresdefaulthostauthentication();配置。筛选器。添加新的主机身份验证筛选器(OAuthDefaults .AuthenticationType));//Web API路由配置maphttpattributorates配置路线。MapHttpRoute(名称: ' DefaultAPI ',route templates : ' API/{ controller }/{ id } ',默认值3360 new { id=RouteParameter .可选});//添加自定义消息处理配置消息处理程序。添加(新的joymesshandler());} }WebApiConfig编写单元测试:
[TestMethod()]public void getTest(){ var id=10;var resultSuccess=$' '值{ id } ';//不加密追踪。没有加密的write line($ ');var url=$'api/ApiTest?id={ id } ';追踪WriteLine($ ' get URL : { URL } ');定义变量响应=http .GetAsync(网址).结果;定义变量结果=响应内容。ReadAsStringAsync().结果;断言。相等(结果,结果成功);追踪WriteLine($ ' result : { result } ');//使用方案一加密追踪WriteLine($)加密案例一");url=$'api/ApiTest?代码=' $'id={id}'.EncryptBase64().EncodeUrl();追踪WriteLine($ ' get URL : { URL } ');http .DefaultRequestHeaders。clear();http .DefaultRequestHeaders。添加(' API _ version ',' 1.0 ');响应=http .GetAsync(网址).结果;结果=响应内容。ReadAsStringAsync().结果;追踪WriteLine($ ' result : { result } ');结果=结果DecryptBase64();追踪写入行($“DecryptBase 64 : { result }”);断言。相等(结果,结果成功);//使用方案2加密通讯追踪WriteLine($)加密案例一");url=$'api/ApiTest?代码=' $'id={id} ' .加密器(messageencryptionversion 1 _ 1 .键)。EncodeUrl();追踪WriteLine($ ' get URL : { URL } ');http .DefaultRequestHeaders。clear();http .DefaultRequestHeaders。添加(' API _ version ',' 1.1 ');响应=http .GetAsync(网址).结果;结果=响应内容。ReadAsStringAsync().结果;追踪WriteLine($ ' result : { result } ');结果=结果。解密器(消息加密版本1_1。KEY);追踪写入行($“DecryptBase 64 : { result }”);断言。相等(结果,结果成功);}ApiTestControllerTests至此为止功能实现完毕.
四。思想延伸
要想更加安全的方案,可以将给每位用户生成不同的私钥,利用俄歇电子能谱加密解密
本演示开源地址:
oschina
https://git.oschina.net/jonneydong/Webapi_Encryption
开源代码库
https://github.com/JonneyDong/Webapi_Encryption
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!