解析 Azure 搜索查询过滤器

Parse Azure search query filter

我的服务器充当用户搜索请求的代理。在 Azure 上请求数据之前,我们需要确保一切都是安全的。为此,我们将某些过滤器添加到查询过滤器中。 假设我的服务器收到此查询:

search=&$top=10&$filter=customer/customerId gt 1 and customer/customerId lt 5

我想拆开它,逐个研究它的过滤器并在其中注入安全过滤器。

我做的第一件事是获取过滤器:

var parsed = HttpUtility.ParseQueryString(query);
var filter = parsed["$filter"];

接下来,我要对其进行处理,以便验证和更改。 阅读 this post 后,我尝试像这样利用 ODataUriParser

// 1. Create a dummy model 
public static IEdmModel GetEdmModel()
{
    var model = new EdmModel();

    EdmEntityType customer = new EdmEntityType("Namespace", "Customer");
    customer.AddKeys(customer.AddStructuralProperty("CustomerId", EdmPrimitiveTypeKind.Int32));
    model.AddElement(customer);

    return model;
}


// 2. Utilize it
static void Foo()
{
    var query = "search=&$top=5001&$filter=Customer/CustomerId eq 1";


    var parsed = HttpUtility.ParseQueryString(query);
    var filter = parsed["$filter"];

    var result = new ODataUriParser(HardCodedTestModel.TestModel, new Uri(filter, UriKind.Relative));
    var parsedFilter = result.ParseFilter();
}

这对我抛出异常,说:

Unhandled exception. Microsoft.OData.UriParser.ODataUnrecognizedPathException: Resource not found for the segment 'Customer

  1. 我做错了什么?
  2. 有没有更简单的方法来实现我想要的?

您的 EDM 模型似乎不包含 entity set,因此不清楚过滤器在过滤什么。 Azure 认知搜索为每个包含实体集“docs”的索引定义了一个 EDM 模型,其类型对应于索引定义。 Azure 认知搜索会将筛选器中的 属性 路径 Customer/CustomerId 解释为名为 Customer 的顶级 Edm.ComplexType 字段的 CustomerId 子字段(使用 OData 术语,文档是实体,Customer 是一个 Complex 属性,而 CustomerIdCustomer 的 属性)。如果您想使用 ODataUriParserODataQueryOptionParser 从过滤器文本中获取语义 AST,您的 EDM 模型将必须包含所有这些模式信息。

也就是说,您可能不需要完整的语义 AST 来验证过滤器表达式的安全性(假设您正在尝试抵御注入攻击之类的事情)。单独使用 OData 过滤器解析器的 lexical stage 可能更简单。然后就可以处理语法AST了。

如果您想要最大程度的控制,您可以随时推出自己的解析器。 OData 的完整 BNF 是 here.