我们正在完全重写现有产品(并且在从PHP改为C#的过程中)。我们在现有产品中遇到的问题之一是授权问题:除非您确保始终在任何地方进行检查,否则人们会看到他们不被允许看到的内容。什么是确保始终检查的最佳位置?我认为数据层是一个很好的地方,但欢迎其他建议。
我们使用NHibernate,因此我们构建了一个提供实体的类。它看起来像这样:
class DataProvider {
TEntity Get<TEntity>(int id) {
return GetSession().Get<TEntity>(id);
}
IQueryable<TEntity> Query<TEntity>()
{
return GetSession().Query<TEntity>();
}
// ...
}
这允许我使用DataProvider.Get<Person>(1)
调用from person in DataProvider.Query<Person>() select person
或执行LINQ查询。使用拦截器将允许我拒绝访问用户没有授权的任何单个对象(尽管可以说我可以在DataProvider.Get
中插入该代码)。当我尝试使用LINQ时,它变得很麻烦。假设我有一个包含100万个实体的表,但我只能访问5个实体。使用Interceptor会检索整个表并测试每个返回的实体,但我只需要其中的5个。我能想到的最好的事情是注入一些自定义SQL来告诉NHibernate要检索哪些对象并忽略所有其他对象。我们已经有一个系统可以确定我们是否可以访问某个对象,让我们假设我们也知道如何查询该对象。
我尝试了什么?
The constant for 'MyQueryable<Person>' is not supported
”,我认为这是由于在NHibernate内部的某个地方进行了投射。我怀疑NHibernate是否允许自定义查询提供程序或可查询。其他人如何处理授权码?你如何确保没有人忘记拨打授权支票?
答案 0 :(得分:1)
我认为你应该看看NHibernate过滤器。
艾恩德的好介绍:http://ayende.com/blog/3993/nhibernate-filters
几年前,我们成功地将NH过滤器用于与您的相似的场景。我已经附上了过滤器的精髓了。在我们的例子中,我们想要控制访问的所有类继承自基类“SecuredObject”。我们在“文件夹”中也有一个“文档”的概念。这有点脱离了上下文,但也许它可以给你一些想法。
<filter name="GrantedSecuredObjectsOnly" condition="
...
Id IN
(SELECT SecurityGrant.SecuredObjectId FROM SecurityGrant WHERE SecurityGrant.SecuredObjectConsumerId=:userId)) OR
(Id IN (SELECT Document.Id FROM Document WHERE Document.FolderId IN (SELECT SecurityGrant.SecuredObjectId FROM SecurityGrant WHERE SecurityGrant.SecuredObjectConsumerId=:userId))
...
"/>
userId当然设置为当前登录的用户ID。
答案 1 :(得分:0)
编辑:我在想什么!
我假设您使用authenticationId / EnteredById
标记数据var userId = ...; //your authentication id
from entity in context.Entities
where context.Entities.Where(x => x.EnteredById == userId && x.Id == entity.Id)
select entity;
我认为应该这样做
var query = new AuthorisedDataQuery<Entity>();
var entities = _dataProvider.Get(query);
编写授权数据查询实现应该非常简单。
具有规范的查询:伪代码
var userId = ... //authentication
var specification = PredicateBuilder.True<Entity>();
specification = PredicateBuilder.And(specification, x => x.EntityId == userId); //default: build from this
var additionalCriterias = ...;
specification = additionalCriterias == null || additionalCriterias.Length == 0
? specification
: GetComposedSpecification(additionalCriterias);
var query = from entity in context.Entities
join anyOtherEntity in context.AnyOtherEntity on entity.EntityId equals anyOtherEntity.Entity.EntityId
where db.Context.Entities.Where(specification).Contains(entity.EntityId)
select entity;
简单地说明您正在尝试实现的是从默认构建查询条件/规范
谓词构建器通过linkkit @ http://www.albahari.com/nutshell/predicatebuilder.aspx