问题描述
背景:结果
我有一个正在使用WCF数据服务(OData的)揭露这是一个非常大的OData模式。不过,微软曾表示,WCF数据服务是的以及该Web API的OData是,他们将去的方式。
所以我研究方法来获得的Web API的OData工作以及WCF数据服务。
问题设置:以固定结果
模型的某些部分并不需要但也有一些。例如,客户列表需要安全性来限制谁可以读取它,但我有其他列表,如产品列表中,任何一个可以查看。
的
客户实体有很多很多的关联,可以达到它。如果算上2 +级协会,许多数以百计的客户均可到达(通过协会)的方式。例如 Prodcuts.First()。Orders.First()。客户
。由于客户是我的系统的核心,你可以用最开始的任何实体,并最终用自己的方式向客户列表关联。
WCF数据服务对我的一种方式通过这样的方法把安全上特定的实体:
[QueryInterceptor(客户)]
公共表达式来;函数功能:LT;客户,布尔>> CheckCustomerAccess()
{
返回DoesCurrentUserHaveAccessToCustomers();
}
我看着网页API的OData,我没有看到这样的事。另外,我很担心,因为似乎我提出的控制器并没有得到调用时关联后面。 (意思是,我不能把安全在 CustomersController
)
我很担心,我将不得不尝试以某种方式枚举所有的方式,协会可以一些如何获得客户,并把安全上的每一个
问:结果
有没有把安全上的特定实体的Web API的方式的OData?(而不必一一列举所有可能以某种方式向下扩展到该实体的关联?)
您需要做的是创建一个新的属性,从EnableQueryAttribute为OData的4(或继承QuerableAttribute这取决于网络API\OData版本你与交谈)并覆盖ValidateQuery(它的同样的方法从QuerableAttribute继承时),以检查是否有合适的SelectExpand属性的存在作为。
要设置一个新的新鲜项目测试这个做到以下几点:
- 创建使用Web API的新ASP.Net项目2
- 创建您的实体框架数据上下文。
- 添加新的Web API的OData 2控制器......控制器。
- 在WebApiConfigRegister(。 ..)方法中添加如下:
代码:
ODataConventionModelBuilder建设者=新ODataConventionModelBuilder();
builder.EntitySet<客户>(客户);
builder.EntitySet<排序>(订单);
builder.EntitySet<&的OrderDetail GT(订单明细);
config.Routes.MapODataServiceRoute(ODATA,ODATA,builder.GetEdmModel());
//config.AddODataQueryFilter();
config.AddODataQueryFilter(新SecureAccessAttribute());
在上面,客户,订单和的OrderDetail是我的实体框架的实体。该config.AddODataQueryFilter(新SecureAccessAttribute())注册我使用SecureAccessAttribute
- SecureAccessAttribute实现如下:
代码:
公共类SecureAccessAttribute:EnableQueryAttribute
{
公共覆盖无效ValidateQuery(HttpRequestMessage要求,ODataQueryOptions queryOptions)
{
如果(queryOptions.SelectExpand = NULL
和!&安培;!queryOptions.SelectExpand.RawExpand =空
和;&安培; queryOptions.SelectExpand.RawExpand.Contains(订单))
{
//这里检查是否允许用户查看订单。
抛出新的InvalidOperationException异常();
}
base.ValidateQuery(请求queryOptions);
}
}
请注意,我允许访问客户控制器,但我限制访问的订单。我已实施的唯一控制器是如下的:
公共类CustomersController:ODataController
{
私人实体DB =新的实体();
[SecureAccess(MaxExpansionDepth = 2)]
公众的IQueryable<客户> GetCustomers的()
{
返回db.Customers;
}
// GET:ODATA /客户(5)
[EnableQuery]
公共SingleResult<客户> GetCustomer([FromODataUri] INT键)
{
返回SingleResult.Create(db.Customers.Where(客户=> customer.Id ==键));
}
}
- 应用的属性,要确保所有操作。它的工作原理完全一样的EnableQueryAttribute。一个完整的样本(包括包装的NuGet结束一切,使之成为一个50MB的下载)可以在这里找到:
我只想还评论了一些其他的解决方案了一下:
- Leyenda的解决方案并不是简单的工作,因为它是周围的其他方式,但在其他方面是超近!事实是,生成器将看在实体框架扩展性,并不会在所有打到客户控制器!我甚至不有一个,如果你删除的安全属性,它仍然会检索订单就好了,如果你添加扩展命令来查询。
- 设置模型构建器将禁止访问实体您在全球范围,并从每个人都删除,所以它不是一个很好的解决方案。
- 奉诏的解决方案可以工作,但你必须手动删除你想保护的项目每个查询,无处不在,这不是一个很好的解决方案。
Background:
I have a very large OData model that is currently using WCF Data Services (OData) to expose it. However, Microsoft has stated that WCF Data Services is dead and that Web API OData is the way they will be going.
So I am researching ways to get Web API OData to work as well as WCF Data Services.
Problem Setup:
Some parts of the model do not need to be secured but some do. For example, the Customers list needs security to restrict who can read it, but I have other lists, like the list of Products, that any one can view.
The Customers entity has many many associations that can reach it. If you count 2+ level associations, the are many hundreds of ways that Customers can be reached (via associations). For example Prodcuts.First().Orders.First().Customer
. Since Customers are the core of my system, you can start with most any entity and eventually associate your way to the Customers list.
WCF Data Services has a way for me to put security on a specific entity via a method like this:
[QueryInterceptor("Customers")]
public Expression<Func<Customer, bool>> CheckCustomerAccess()
{
return DoesCurrentUserHaveAccessToCustomers();
}
As I look at Web API OData, I am not seeing anything like this. Plus I am very concerned because the controllers I am making don't seem to get called when an association is followed. (Meaning I can't put security in the CustomersController
.)
I am worried that I will have to try to somehow enumerate all the ways that associations can some how get to customers and put security on each one.
Question:
Is there a way to put security on a specific entity in Web API OData? (Without having to enumerate all the associations that could somehow expand down to that entity?)
What you need to do is to create a new Attribute inheriting from EnableQueryAttribute for OData 4 (or QuerableAttribute depending on which version of Web API\OData you are talking with) and override the ValidateQuery (its the same method as when inheriting from QuerableAttribute) to check for the existence of a suitable SelectExpand attribute.
To setup a new fresh project to test this do the following:
- Create a new ASP.Net project with Web API 2
- Create your entity framework data context.
- Add a new "Web API 2 OData Controller ..." controller.
- In the WebApiConfigRegister(...) method add the below:
Code:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Customer>("Customers");
builder.EntitySet<Order>("Orders");
builder.EntitySet<OrderDetail>("OrderDetails");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
//config.AddODataQueryFilter();
config.AddODataQueryFilter(new SecureAccessAttribute());
In the above, Customer, Order and OrderDetail are my entity framework entities. The config.AddODataQueryFilter(new SecureAccessAttribute()) registers my SecureAccessAttribute for use.
- SecureAccessAttribute is implemented as below:
Code:
public class SecureAccessAttribute : EnableQueryAttribute
{
public override void ValidateQuery(HttpRequestMessage request, ODataQueryOptions queryOptions)
{
if(queryOptions.SelectExpand != null
&& queryOptions.SelectExpand.RawExpand != null
&& queryOptions.SelectExpand.RawExpand.Contains("Orders"))
{
//Check here if user is allowed to view orders.
throw new InvalidOperationException();
}
base.ValidateQuery(request, queryOptions);
}
}
Please note that I allow access to the Customers controller, but I limit access to Orders. The only Controller I have implemented is the one below:
public class CustomersController : ODataController
{
private Entities db = new Entities();
[SecureAccess(MaxExpansionDepth=2)]
public IQueryable<Customer> GetCustomers()
{
return db.Customers;
}
// GET: odata/Customers(5)
[EnableQuery]
public SingleResult<Customer> GetCustomer([FromODataUri] int key)
{
return SingleResult.Create(db.Customers.Where(customer => customer.Id == key));
}
}
- Apply the attribute in ALL actions that you want to secure. It works exactly as the EnableQueryAttribute. A complete sample (including Nuget packages end everything, making this a 50Mb download) can be found here: http://1drv.ms/1zRmmVj
I just want to also comment a bit on some other solutions:
- Leyenda's solution does not work simply because it is the other way around, but otherwise was super close! The truth is that the builder will look in the entity framework to expand properties and will not hit the Customers controller at all! I do not even have one, and if you remove the security attribute, it will still retrieve the orders just fine if you add the expand command to your query.
- Setting the model builder will prohibit access to the entities you removed globally and from everyone, so it is not a good solution.
- Feng Zhao's solution could work, but you would have to manually remove the items you wanted to secure in every query, everywhere, which is not a good solution.
这篇关于每个实体的Web API的OData安全的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!