WebApi 如何 优雅的 对 输入输出 解密加密

原文:WebApi 如何 优雅的 对 输入输出 解密加密

这不是变态的想法, 这只是对现实需求的转化.

因为有密文, 所以本文不适用于浏览器到服务端的数据交换;

只适用于服务端到服务端的数据传输.

用传统的方法对输入输出做加解密, 无非就是在入口处做操作. 但是 WebApi 的参数如果接收的是一串加密字符串, 那基本上等于和 WebApi 强大的模型绑定 Say baybay 了.

要加解密, 又想利用 WebApi 的便利, 有没有什么好的方法呢? 用 ActionFilter ? ModelBinder ?? 好像不能很好的解决(没有仔细的研究).

参考了 Microsoft.AspNet.WebApi.MessageHandlers.Compression 的写法, 我写了个简单的实现..

将返回结果加密

声明 ActionFilter

用以指示后续的处理程序, 哪些Action结果是要密的; 如果需要加密输出, 则在 Response 的 Header 的 ContentType 里加上 encrypt 参数

  [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
  public class EncryptAttribute : ActionFilterAttribute
  {
      public bool Ignore { get; set; }

      public override async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
      {
          await base.OnActionExecutedAsync(actionExecutedContext, cancellationToken);
          if (!this.Ignore)
          {
              actionExecutedContext.Response.Content.Headers.ContentType.Parameters.Add(new System.Net.Http.Headers.NameValueHeaderValue("encrypt", ""));
          }
      }
  }

属性: Ignore , 如果值为 true , 则告诉处理程序, 结果不需要加密;

注意 AllowMutltiple 一定是 false, 避免 Controller 和 Action 上的 Filter 交叉.

使用 EncryptAttribute

    [Encrypt]
    public class TestController : ApiController
    {
        public Test Get()
        {
            return new Test()
            {
                ID = 1,
                Name = "xling"
            };
        }

        [Encrypt(Ignore = true)]
        public Test Post(Test test)
        {
            return test;
        }
    }

派生 DelegatingHandler

重写 SendAsync 方法

    public class CryptoHandler : DelegatingHandler
    {
        ...
        ...
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var response = await base.SendAsync(request, cancellationToken);
            return await this.HandleResponse(request, response, cancellationToken);
        }

        ...
        ...
        private async Task<HttpResponseMessage> HandleResponse(HttpRequestMessage request, HttpResponseMessage response, CancellationToken cancellationToken)
        {
            if (response.Content != null && response.Content.Headers.ContentType.Parameters.Any(p => string.Equals(p.Name, "encrypt", StringComparison.OrdinalIgnoreCase)))
            {
                var inputBytes = await response.Content.ReadAsByteArrayAsync();
                var encryptByte = AesHelper.Encrypt(inputBytes, KEY);

                var base64 = Convert.ToBase64String(encryptByte);
                var encryptedContent = new StringContent(base64);

                encryptedContent.Headers.Clear();
                response.Content.Headers.CopyTo(encryptedContent.Headers);
                response.Content = encryptedContent;

                return response;
            }

            return response;
        }

    }

在 HandleResponse 方法里, 首先判断 Response Header 的 ContentType 里是否包含 encrypt 这个参数.

跟据生命周期, 这里的 encrypt 就是上面的 ActionFilter 写进来的.

紧接着就是把返回内容当作字符串加密,并转化为 Base64 格式, 写进 StringContent 里.

然后把原始的 Response Header 覆盖到新的 StringContent 里去.

使用 CryptoHandler

修改 Global 的 Application_Start 方法, 在最后面加上:

GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new CryptoHandler());

看一下输出的 Response Header

加密输出 Response Header

解密收到的请求

对CryptoHandler扩展

上面的 CryptoHandler 只对 Response 做了处理. 这里我们要修改 SendAsync 方法, 使它能够将传入的加密数据还原成可以被 WebApi 的 ModelBinder 识别的数据.

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            request = await this.HandleRequest(request, cancellationToken);
            var response = await base.SendAsync(request, cancellationToken);
            return await this.HandleResponse(request, response, cancellationToken);
        }

        private async Task<HttpRequestMessage> HandleRequest(HttpRequestMessage request, CancellationToken cancellation)
        {
            if (request.Content?.Headers.ContentType?.Parameters?.Any(y => string.Equals(y.Name, "encrypt", StringComparison.OrdinalIgnoreCase)) == true)
            {
                var input = await request.Content.ReadAsStringAsync();
                var inputBytes = Convert.FromBase64String(input);
                var decryptedBytes = AesHelper.Decrypt(inputBytes, KEY);

                //var str = Encoding.UTF8.GetString(decryptedBytes);

                var stm = new MemoryStream(decryptedBytes);
                var decryptedContent = new StreamContent(stm);
                request.Content.Headers.CopyTo(decryptedContent.Headers);
                request.Content = decryptedContent;

                return request;

            }

            return request;
        }

跟加密一样, 解密的第一步也是判断 ContentType 里是否包含参数 encrypt.

接着就是把请求的内容按 string 取出, 并用 base64 解码(因为上一步产生的结果, 我们用 base64 转义了.)

然后对结果解密, 并写入 StreamContent, 替换 request 的 Content.

在运行下去, 就到 Action 里去了.

看一下请求示例

加密提交 以 raw 方式提交数据

加密提交 Request Header

提交数据的时候, 必须告诉 Content-Type , 加密之前是什么格式的, 而且还要带上 encrypt .

上图示例, 我提交的数据在加密之前是 xml 数据.

其它

CryptoHandler.cs 完整代码

using XXX.Common;
using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Extensions.Compression.Core.Extensions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace XXX.XXX.XXX
{
    public class CryptoHandler : DelegatingHandler
    {

        private static string KEY = "FF545E10-EDB8-4086-861C-AADFAED015C3";

        public static void Init(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentNullException(key);

            KEY = key;
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            request = await this.HandleRequest(request, cancellationToken);
            var response = await base.SendAsync(request, cancellationToken);
            return await this.HandleResponse(request, response, cancellationToken);
        }

        private async Task<HttpRequestMessage> HandleRequest(HttpRequestMessage request, CancellationToken cancellation)
        {
            if (request.Content?.Headers.ContentType?.Parameters?.Any(y => string.Equals(y.Name, "encrypt", StringComparison.OrdinalIgnoreCase)) == true)
            {
                var input = await request.Content.ReadAsStringAsync();
                var inputBytes = Convert.FromBase64String(input);
                var decryptedBytes = AesHelper.Decrypt(inputBytes, KEY);

                //var str = Encoding.UTF8.GetString(decryptedBytes);

                var stm = new MemoryStream(decryptedBytes);
                var decryptedContent = new StreamContent(stm);
                request.Content.Headers.CopyTo(decryptedContent.Headers);
                request.Content = decryptedContent;

                return request;

            }

            return request;
        }

        private async Task<HttpResponseMessage> HandleResponse(HttpRequestMessage request, HttpResponseMessage response, CancellationToken cancellationToken)
        {
            if (response.Content != null && response.Content.Headers.ContentType.Parameters.Any(p => string.Equals(p.Name, "encrypt", StringComparison.OrdinalIgnoreCase)))
            {
                var inputBytes = await response.Content.ReadAsByteArrayAsync();
                var encryptByte = AesHelper.Encrypt(inputBytes, KEY);

                var base64 = Convert.ToBase64String(encryptByte);
                var encryptedContent = new StringContent(base64);

                encryptedContent.Headers.Clear();
                response.Content.Headers.CopyTo(encryptedContent.Headers);
                response.Content = encryptedContent;

                return response;
            }

            return response;
        }

    }
}

原文地址:https://www.cnblogs.com/lonelyxmas/p/11121933.html

时间: 2024-08-30 14:10:21

WebApi 如何 优雅的 对 输入输出 解密加密的相关文章

asar 如何解密加密?electron 的 asar 的具体用法

来源:https://newsn.net/say/electron-asar.html 在electron中,asar是个特殊的代码格式.asar包里面包含了程序猿编写的代码逻辑.默认情况下,这些代码逻辑,是放置在resource/app目录下面的,明文可见,这样的话,也就有了代码加密(asar打包)的需求 asar 如何解密加密?electron 的 asar 的具体用法(图12-1) 在本篇文章中,苏南大叔将要讲述的内容就是:asar工具的使用.本文的模特是:在mac下面,使用electro

playfair密码解密加密

#include #include #include #include int A[1000][1000];//转化矩阵 int a[1000][1000];//单位矩阵[A E] int B[1000][1000];//矩阵的逆矩阵A^(-1) int ming[1000][1000];//明文矩阵 int mi[1000][1000];//密文矩阵 int n;//矩阵的阶数 void input()//输入数据 { int i, j; for( i = 1; i <= n; i++ ) f

C#对字符串的简单加密解密过程C#的SQL数据库登陆密码的加密解密加密还原直接复制代码使用即可

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography; using System.IO; namespace PDAPrint { class ClassSecurityString { public static string encryptKey = "www.hanma-scan.com"; /

ansible 解密 加密 文件

mac用户可以通过brew命令安装: brew install ansible 首先把密码存在一个固定的文件里,比如  ~/.vault_pass.txt ,方便使用. 如果一个配置文件variables.yml 的内容已经用ansible加密了,如何解密: ansible-vault decrypt --vault-password-file ~/.vault_pass.txt variables.yml 如何加密一个文件: ansible-vault encrypt --vault-pass

重装系统后用!解密加密.exe加密文件怎么給提取出来

BASE64解密加密

package com.mai.base64;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream; import org.juni

utf-8 解密加密

// 之前的在使用会报警告 urlStr是请求路径 NSString *decodeStr = [urlStr stringByRemovingPercentEncoding];//utf-8解码 NSString *encodeStr = [decodeStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"`#%^{}\"[

075_解密加密

https://blog.csdn.net/itsme_web/article/details/81017246 https://blog.csdn.net/itsme_web/article/details/76229260 调用邮件模板 https://blog.csdn.net/itsme_web/article/details/75271801  用apex代码通过Trigger提交审批/在List View上批量提交与审批 button 调用 class https://blog.cs

加密解密以及私有CA的实现

一.加密和解密 什么是加密:加密之前为明文,加密后是密文,将明文转换为密文的过程就是加密. 1. 对称加密 提供算法本身,加密和解密使用的是同一个密钥,用以保证数据的机密性.但安全性依赖于密钥,而非算法. 对称加密的优点是运算特别快:缺点是安全几乎全部依赖于密钥(算法基本上是公开的),当通信对象很多的时候,很难对密钥进行有效管理. 常见算法: DES(Data Encrption Standard):早期的算法,公开可以使用的,56bit密码长度,惨遭淘汰. 3DES:DES后DES再DES A