3

我正在尝试使用 NHibernate 实现特权,而我想要做的是,每次有一个 Select 查询时,检查返回类型是什么,如果它是启用安全性的类型(例如发票),我想添加限制到 ICriteria 对象,以限制仅检索某些记录(根据用户是否已阅读全部或阅读自己的权限)。

我设法使用

NHibernater.Event.IPreUpdateEventListener
NHibernater.Event.IPreInsertEventListener

但不幸的IPreLoadEventListener是,在查询数据库后调用,因此这是浪费,因为过滤将在计算机本地完成,而不是由数据库完成。

有谁知道 NHibernate 是否提供了在执行查询之前调用的某种事件?

4

2 回答 2

2

你不能通过使用过滤器来实现这一点吗?

更多信息可以在这里找到

我在我的一个项目中将它与拦截器结合使用:

我有一些实体,每个用户都可以从中创建实例,但只有创建它们的用户才能查看/修改这些实例。其他用户看不到用户 X 创建的实例。

为此,我创建了一个 interface IUserContextAware。“用户上下文感知”的实体实现了这个接口。

在构建会话工厂时,我创建了必要的过滤器:

 var currentUserFilterParametersType = new Dictionary<string, NHibernate.Type.IType> (1);
 currentUserFilterParametersType.Add (CurrentUserContextFilterParameter, NHibernateUtil.Guid);
 cfg.AddFilterDefinition (new FilterDefinition (CurrentUserContextFilter,
                                                           "(:{0} = UserId or UserId is null)".FormatString (CurrentUserContextFilterParameter),
                                                           currentUserFilterParametersType,
                                                           false));

完成后,我需要定义额外的过滤条件:

 foreach( var mapping in cfg.ClassMappings )
 {
    if( typeof (IUserContextAware).IsAssignableFrom (mapping.MappedClass) )
    {
       // The filter should define the names of the columns that are used in the DB, rather then propertynames.
      // Therefore, we need to have a look at the mapping information.

      Property userProperty = mapping.GetProperty ("UserId");

      foreach( Column c in userProperty.ColumnIterator )
      {
          string filterExpression = ":{0} = {1}";

          // When the BelongsToUser field is not mandatory, NULL should be taken into consideration as well.
          // (For instance: a PrestationGroup instance that is not User-bound (that can be used by any user), will have
          //  a NULL value in its BelongsToUser field).
          if( c.IsNullable )
          {
              filterExpression = filterExpression + " or {1} is null";
          }

          mapping.AddFilter (CurrentUserContextFilter, "(" + filterExpression.FormatString (CurrentUserContextFilterParameter, c.Name) + ")");
          break;
     }
 }

现在,每当我实例化一个ISession,我指定应该使用某个拦截器:

此拦截器确保填充过滤器中的参数:

    internal class ContextAwareInterceptor : EmptyInterceptor
    {
        public override void SetSession( ISession session )
        {
            if( AppInstance.Current == null )
            {
                return;
            }

            // When a User is logged on, the CurrentUserContextFilter should be enabled.
            if( AppInstance.Current.CurrentUser != null )
            {
                session.EnableFilter (AppInstance.CurrentUserContextFilter)
                                            .SetParameter (AppInstance.CurrentUserContextFilterParameter,
                                                           AppInstance.Current.CurrentUser.Id);

            }
        }
}
于 2011-02-07T15:11:23.390 回答
2

如果您能够使用它,请查看Rhino.Security它完全符合您的要求。即使你无法使用它,你也可以看到他对这个问题的实现。

于 2011-02-07T15:18:40.970 回答