受欢迎的博客标签

Asp.Net Core中间件拦截Http流将请求和响应数据进行加密传输

Published

前沿:最近有个需求,出于安全方面的考虑,需要将请求和响应数据进行加密传输
最终请求如图所示:

请求是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");
            }
        }
    }