更新时间:2023-02-14 19:57:52
您需要做的是创建一个新的属性,从EnableQueryAttribute为OData的4(或继承QuerableAttribute这取决于网络API\OData版本你与交谈)并覆盖ValidateQuery(它的同样的方法从QuerableAttribute继承时),以检查是否有合适的SelectExpand属性的存在作为。
要设置一个新的新鲜项目测试这个做到以下几点:
代码:
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: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 ==键));
}
}
我只想还评论了一些其他的解决方案了一下:
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:
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.
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));
}
}
I just want to also comment a bit on some other solutions: