前沿:最近有个需求,出于安全方面的考虑,需要将请求和响应数据进行加密传输
最终请求如图所示:
请求是Json数据,包括appKey,query和signkey字段,响应字段包括state,data,msg,version,signKey需要补充说明的就是加密方式。query和data的数据是用AES加密的,signKey是rsa加密的是AES的密钥。
针对这种情况,利用中间件来处理请求响应流是最好不过了。
于是开始自己捣鼓httpContext.Request.Body和httpContext.Response.Body,发现读取了request.Body后 想要再向起写入数据就不行了。然后得到各路大神相助,这里感谢@码农*白难度的帮助,参考了他提的issue,最终解决了。代码如下:
public class EncryptDecryptMiddleware
{
private readonly RequestDelegate _next;
public EncryptDecryptMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
//判断是否为加密请求
if (httpContext.Request.Headers.ContainsKey("aesrequest"))
{
//创建http的原始请求和响应流
var reqOrigin = httpContext.Request.Body;
var resOrigin = httpContext.Response.Body;
try
{
using (var newReq = new MemoryStream())
{
//替换request 流
httpContext.Request.Body = newReq;
using (var newRes = new MemoryStream())
{
//替换response流
httpContext.Response.Body = newRes;
string reqStr;
using (var streamReader = new StreamReader(reqOrigin))
{
//读取原始请求的流的内容
reqStr = streamReader.ReadToEnd();
}
//假设这里对读取的内容进行解密
string writeStr = JsonConvert.SerializeObject(new
{
Name = "test"
});
//解密完之后把解密后内容写入新的request流去
using (var streamWriter = new StreamWriter(newReq))
{
streamWriter.Write(writeStr);
streamWriter.Flush();
//此处一定要设置=0,否则controller的action里模型绑定不了数据
newReq.Position = 0;
//进入action
await _next(httpContext);
}
string resStr;
//读取action返回的结果
using (var streamReader = new StreamReader(newRes))
{
newRes.Position = 0;
resStr = streamReader.ReadToEnd();
}
//假设这里对action返回的结果进行加密
string resWriteStr = "hello world";
using (var streamWriter = new StreamWriter(resOrigin))
{
streamWriter.Write(resWriteStr);
}
}
}
}
finally
{
//将原始的请求和响应流替换回去
httpContext.Request.Body = reqOrigin;
httpContext.Response.Body = resOrigin;
}
}
else
{
await httpContext.Response.WriteAsync("don't receive non-encrpt request");
}
}
}