NHibernate:更改授权查询

时间:2012-05-29 09:04:32

标签: .net linq nhibernate authorization

我们正在完全重写现有产品(并且在从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要检索哪些对象并忽略所有其他对象。我们已经有一个系统可以确定我们是否可以访问某个对象,让我们假设我们也知道如何查询该对象。

我尝试了什么?

  • 拦截器(太迟了,只需要5个就检索100万个物体)。
  • 事件(IPostLoadEvent最接近我需要的,但它也太晚了。)
  • 自定义NhQueryable和DefaultQueryProvider。这引发了一个异常:“The constant for 'MyQueryable<Person>' is not supported”,我认为这是由于在NHibernate内部的某个地方进行了投射。我怀疑NHibernate是否允许自定义查询提供程序或可查询。
  • OnPrepareStatement拦截器。这非常难看。它允许我编辑SQL,但我得到的只是一个字符串。这样可行,但我希望有一种更优雅的方式来做同样的事情。

其他人如何处理授权码?你如何确保没有人忘记拨打授权支票?

2 个答案:

答案 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