3

我们正在完全重写现有产品(并且正在从 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. 使用拦截器将允许我拒绝访问用户无权访问的任何单个对象(尽管可以说我可以将该代码插入DataProvider.Get)。当我尝试使用 LINQ 时,它变得很麻烦。假设我有一个包含 100 万个实体的表,但我只能访问 5 个实体。使用拦截器将检索整个表并测试每个返回的实体,但我只需要其中的 5 个。我能想象的最好的事情是注入一些自定义 SQL 来告诉 NHibernate 检索哪些对象并忽略所有其他对象。我们已经有一个系统可以确定我们是否可以访问一个对象,假设我们也知道如何从中进行查询。

我尝试了什么?

  • 拦截器(为时已晚,只需要 5 个时检索 100 万个对象)。
  • 事件(IPostLoadEvent 最接近我的需要,但也为时已晚)。
  • 自定义 NhQueryable 和 DefaultQueryProvider。这会引发一个异常:“ The constant for 'MyQueryable<Person>' is not supported”,我认为这是由于 NHibernate 内部某个深处的投射所致。我怀疑 NHibernate 的设计目的是允许自定义查询提供程序或可查询。
  • OnPrepareStatement 拦截器。这是难以置信的丑陋。它允许我编辑 SQL,但我得到的只是一个字符串。这会起作用,但我希望有一种更优雅的方式来做同样的事情。

其他人如何处理他们的授权码?您如何确保没有人忘记调用授权检查?

4

2 回答 2

1

我认为你应该看看 NHibernate 过滤器。

Ayende 的精彩介绍在这里: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。

于 2012-05-31T20:04:45.063 回答
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的谓词构建器

于 2012-05-29T10:22:35.247 回答