使用jsoncpp时从JSon中删除私有数据的最佳方法

时间:2017-08-01 08:46:18

标签: c++ json jsoncpp

问题很简单。一些JSon数据与服务器交换。 由于通信非常复杂,我需要将日志作为复杂信息,以查看是否:

  • 服务器发送代码
  • 省略的新值
  • 发送错字的JSon
  • ans so

但与此同时,任何私人数据都应该通过虚拟数据进行遮蔽。

所以请参阅日志:

{
    "secuityToken" : "asdasdgas234fsdfsaD",
    "message" : "user private message"
}

应该看到这样的事情:

{
    "secuityToken" : "********",
    "message" : "*******"
}

我的代码是C ++,所以jsoncpp正在使用中。 我能看到的最好的方法是:

bool ProcessServerMessage(const std::string& message)
{
    Json::Value jsonValue;
    Json::Reader reader;
    if (reader.parse(sMessage, jsonValue, false))
    {
        auto logValue =  ShadowPrivateData(jsonValue, listOfKeysWithPrivateData);
        LOG() << " JSOn recived: " << logValue;
        …
    }

ShadowPrivateData应该是什么样子,最通用的?

2 个答案:

答案 0 :(得分:3)

至于我,这里有一个简单明了的方法。只需为ShadowPrivateData的所有成员递归调用jsonValue即可。在每个递归步骤中,您应确定jsonValue是否为数组,对象或两者都不是,并正确迭代它。请使用isArrayisObject

在迭代对象或数组字段时,如果字段不是聚合(对象或数组),请在listOfKeysWithPrivateData中搜索它的名称。如果在列表中找到了字段的名称,请确定字段的类型(使用isStringisDoubleisIntegral等)并将字段替换为适当的值:用星号替换字符串,用零填充数字等

listOfKeysWithPrivateData声明为std::set<std::string>或类似的内容,以执行对数搜索而不是线性搜索。

如何遍历聚合对象?使用getMemberNames表示对象,使用size表示数组。换句话说,jsoncpp为json对象内省提供了完整的方法集合。

正确实施后,此方法应审核jsonValue中的所有敏感数据,而忽略其复杂性。

答案 1 :(得分:0)

所以我选择了@Sergey提案并且有类似的东西:

// in header
class CJSONUtils
{
public:
    static Json::Value HidePrivateData(const Json::Value& value,
                                       const std::vector<std::string>& pathSufixes);

private:
    static void ShadowPrivateData(Json::Value& value,
                                  const std::vector<std::string>& pathSufixes,
                                  const std::string& sPath);

    static bool IsPrivatePath(const std::string& sPath,
                              const std::vector<std::string>& pathSufixes);

    static std::string MaskPrivateText(const std::string& sPrivateText);
};

// in cpp
#include "JSONUtils.h"
#include "StringUtils.h"
#include <algorithm>
#include <json/json.h>

using namespace std;
using namespace Json;

Value CJSONUtils::HidePrivateData(const Value& value,
                                  const vector<string>& pathSufixes)
{
    Value result { value };
    ShadowPrivateData(result, pathSufixes, {});
    return result;
}

void CJSONUtils::ShadowPrivateData(Value& value,
                                   const vector<string>& pathSufixes,
                                   const string& sPath)
{
    switch (value.type())
    {
        case nullValue:
        case intValue:
        case uintValue:
        case realValue:
        case booleanValue:
            break;

        case stringValue:
            if (IsPrivatePath(sPath, pathSufixes))
            {
                value = Value { MaskPrivateText(value.asString()) };
            }
            break;

        case arrayValue:
            for (auto& arrayValue : value)
            {
                ShadowPrivateData(arrayValue, pathSufixes, sPath + "[]");
            }
            break;

        case objectValue:
            for (auto it = value.begin(); it != value.end(); ++it)
            {
                ShadowPrivateData(*it, pathSufixes, sPath + "." + it.key().asString());
            }
            break;
    }
}

bool CJSONUtils::IsPrivatePath(const string& sPath,
                               const vector<string>& pathSufixes)
{
    return std::any_of(pathSufixes.begin(),
                       pathSufixes.end(),
                       [&](const string& sSufix)
                       {
                           return EndsWith(sPath, sSufix);
                       });
}

std::string CJSONUtils::MaskPrivateText(const std::string& sPrivateText)
{
    if (sPrivateText.length() < 15)
    {
        return std::string(sPrivateText.length(), '*');
    }
    ostringstream result;
    result << "< *" << sPrivateText.length() << " characters * >";
    return result.str();
}

现在,由于Json::Value重载了流操作符,因此可以像这样使用:

LOG() << " JSON received: " << CJSONUtils::HidePrivateData(jsonRoot, listOfPrivateItemsPaths);

我为它编写了测试(gtest),它就像魅力一样。