简体   繁体   English

WebAPI可以在响应之前更改输出吗?

[英]Can WebAPI change output just before response?

I'm building a WebAPI for an external mobile company ( all I do is exposing services). 我正在为外部移动公司构建WebAPI(我所做的只是公开服务)。

Right now , our DB uses non-encrypted values for columns like : 现在,我们的数据库对列使用未加密的值,例如:

  • ObjectID 对象ID
  • PolicyID 策略ID
  • etc.. 等等..

But now , when we expose it , and I need to encrypt values. 但是现在,当我们公开它时,我需要加密值。 ( only server can decrypt values , the mobile company doesn't care about the actual values). (只有服务器可以解密值,移动公司不在乎实际值)。

I don't want to start digest every Stored Procedure response manually and replace values with encrypted ones. 我不想手动开始摘要每个存储过程响应,并用加密的值替换值。 ( don't forget that our internal server does not uses encrypted values - it uses data regularly). (不要忘记,我们的内部服务器使用加密的价值-它经常性地使用数据)。

OK Here's a live example : 好,这是一个实时示例:

I have this controller code : 我有这个控制器代码:

[HttpGet]
[ActionName("test2")]
public HttpResponseMessage test2(int id)
{
   var Data = GetDataFromSource_1();
            // or from GetDataFromSource_2(); 
   return Request.CreateResponse(HttpStatusCode.OK, Data);
}

Where GetDataFromSource_1 is via dynamic list (just to simulate a source) 其中GetDataFromSource_1是通过动态列表(仅用于模拟源)

public IEnumerable GetDataFromSource_1()
{
    List<dynamic> lst = new List<dynamic>();
    lst.Add(new
    {
        objId = 1,
        myOtherColumn = 5
    });
    lst.Add(new
    {
        objId = 2,
        myOtherColumn = 8
    });
    return lst;
}

And

GetDataFromSource_2 is via DataTable ( just to simulate another source) GetDataFromSource_2是通过DataTable(仅用于模拟另一个源)

public DataTable GetDataFromSource_2()
{
    DataTable dt = new DataTable("myTable");
    dt.Columns.Add("objId", typeof(int));
    dt.Columns.Add("myOtherColumn", typeof(int));
    DataRow row = dt.NewRow();
    row["objId"] = 1;
    row["myOtherColumn"] = 5;
    dt.Rows.Add(row);
    row = dt.NewRow();
    row["objId"] = 2;
    row["myOtherColumn"] = 8;
    dt.Rows.Add(row);
    return dt;
}

Both yields this json response: 两者都产生以下json响应:

{"Result":{"Success":true,"Message":""},"Data":[{"objId":1,"myOtherColumn":5},{"objId":2,"myOtherColumn":8}]} { “结果”:{ “成功”:真, “消息”: “”}, “数据”:[{ “OBJID”:1, “myOtherColumn”:5},{ “OBJID”:2 “myOtherColumn”: 8}]}

Question

How (and where) can I scan the content of the response ( which is going to be sent) and replace for every column in ( and only for them) : 我如何(以及在​​哪里)扫描响应的内容(将要发送的内容),并替换( 适用于它们)中的每一列:

  • ObjectID 对象ID
  • PolicyID 策略ID
  • etc.. 等等..

to an encrypted value ? 加密值?

For example : 例如 :

I Would like the output to be : 我希望输出为:

{
    "Result": {
        "Success": true,
        "Message": ""
    },
    "Data": [{
        "objId": "XXX_the_encrypted_valueXXX",
        "myOtherColumn": 5
    }, {
        "objId": "XXX_the_encrypted_valueXXX":  ,
        "myOtherColumn": 8
    }]
}

(where "XXX_the_encrypted_valueXXX" is an encrypted value of the old value.) (其中"XXX_the_encrypted_valueXXX"是旧值的加密值。)

NB it's assumable that I have Utils.Encrypt(string st) method. 注意,我可以使用Utils.Encrypt(string st)方法。

Also , we dont have entities so i can not decorate an entity . 另外,我们没有实体,所以我无法装饰实体。 I need to plugin when the json is created 创建json时需要插入

I think you should decorate the encrypted properties with an Attribute : 我认为您应该使用Attribute装饰加密的Attribute

[JsonEncryptValue]
public Guid ObjectID {get;set;}

And then add a JsonConverter that will handle only properties that have a JsonEncryptValue attribute on them. 然后添加一个JsonConverter ,该JsonConverter将仅处理具有JsonEncryptValue属性的属性。 You can re-write their value easily. 您可以轻松地重新编写它们的值。

And then all you need to do is add your JsonConverter to the JsonSerializer in the WebApiConfig.cs file: 然后,所有你需要做的就是你的加入JsonConverterJsonSerializerWebApiConfig.cs文件:

    JsonMediaTypeFormatter jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
    JsonSerializerSettings jSettings = new Newtonsoft.Json.JsonSerializerSettings()
    {
        Formatting = Formatting.Indented,
        DateTimeZoneHandling = DateTimeZoneHandling.Utc
    };

    jSettings.Converters.Add(new EncryptionJsonConverter());
    jsonFormatter.SerializerSettings = jSettings;

What you can do is create a custom DelegatingHandler by deriving it and supplying your own implementation and register it your config.MessageHandlers . 您可以做的是通过派生自定义DelegatingHandler并提供您自己的实现,然后将其注册为config.MessageHandlers

So we need a handler and a recursive method which iterates the entire JSON. 因此,我们需要一个处理程序和一个递归方法来迭代整个JSON。 We'll use the answer provided in Searching for a specific JToken by name in a JObject hierarchy : 我们将使用在JObject层次结构中按名称搜索特定的JToken中提供的答案:

private static void FindTokens(JToken containerToken, string name, List<JToken> matches)
{
    if (containerToken.Type == JTokenType.Object)
    {
        foreach (JProperty child in containerToken.Children<JProperty>())
        {
            if (child.Name == name)
            {
                matches.Add(child.Value);
            }
            FindTokens(child.Value, name, matches);
        }
    }
    else if (containerToken.Type == JTokenType.Array)
    {
        foreach (JToken child in containerToken.Children())
        {
            FindTokens(child, name, matches);
        }
    }
}

And the complete handler will look as following: 完整的处理程序将如下所示:

public class JsonEncrypterHandler : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);
        var returnedJson = await response.Content.ReadAsStringAsync();

        JObject jObj = JObject.Parse(returnedJson);

        List<JToken> objIdTokens = new List<JToken>();
        List<JToken> policyIdTokens = new List<JToken>();

        FindTokens(jObj, "objid", objIdTokens);
        FindTokens(jObj, "policyid", policyIdTokens);

        foreach (JValue objId in objIdTokens)
        {
            objId.Value = Utils.Encrypt(objIdValue);
        }

        foreach (JValue policyId in policyIdTokens)
        {
            policyId.Value = Utils.Encrypt(policyIdTokens);
        }

        response.Content = JsonConvert.SerializeObject(jObj);
        return response;
    }
}

I think you have to create customer attribute. 我认为您必须创建客户属性。 Decorate all your action or controller with that attribute. 使用该属性装饰您的所有操作或控制器。

In that on you have to read result and deserialize back to Json object or .net object. 在那您必须读取结果并反序列化回Json对象或.net对象。

Following link will help you on that. 以下链接将帮助您。

http://damienbod.wordpress.com/2014/01/04/web-api-2-using-actionfilterattribute-overrideactionfiltersattribute-and-ioc-injection/ http://damienbod.wordpress.com/2014/01/04/web-api-2-using-actionfilterattribute-overrideactionfiltersattribute-and-ioc-injection/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM