11

我定义了几个角色,每个角色对内容和媒体项目都有不同的限制,我想限制基于当前登录用户的访问权限返回的搜索结果,而不是显示结果然后向用户呈现“拒绝访问”页面。Extranet\anonymous 显然可以访问某些内容,因此无论如何都应该为所有用户返回它们。

安全性遵循标准的Sitecore 实践,因此将使用角色继承(角色内的角色),因此也需要考虑到这一点。

我在Advanced Database Crawler 模块中看不到任何有用的信息,并且我查看了 Sitecore 搜索和索引指南(版本 6.6版本 7),但找不到任何有关对应用于项目的安全性进行索引的信息。以下文章有一些建议:

这感觉很“脏”,并且可能会出现性能问题,尤其是在返回大量项目时。此外,(见评论)分页结果的问题。

上面看起来更现实,并且会根据索引的安全角色过滤掉结果,显然需要扩展角色以处理角色内的角色。我在这里担心的是,当我们特别需要拒绝/限制某些角色对内容项的访问时,我们需要处理被拒绝的权限(我知道这不是推荐的做法,但有一个非常具体的需要总是拒绝)。

我目前正处于计划阶段,因此随着今天 Sitecore 7 的发布,如果这样可以使生活更轻松,还可以使用更新的 Lucene 库和/或 SOLR - 当然假设某些模块,如WebForms 用于营销人员电子邮件营销管理器很快就会更新。

考虑到安全性,人们使用哪些解决方案来返回搜索结果?除了上面的链接问题还有其他选择吗?也许我可以利用 Sitecore 7 中的某些东西,更新的 Lucene 库或 SOLR?

我宁愿保留这一切“开箱即用”的 Sitecore,并且尽可能不使用其他第三方搜索产品。

4

4 回答 4

16

对 Klaus 的建议稍作替代:

Sitecore.ContentSeach.config你会发现一个名为的管道contentSearch.getGlobalSearchFilters

添加到此管道的处理器将应用于任何查询,因此如果我们加入一个基于角色应用过滤器的处理器,我们就很好了。

计算场

首先,我们希望将一个计算字段添加到我们的索引配置中:

<fields hint="raw:AddComputedIndexField">
   <field fieldName="read_roles"           returnType="stringCollection">Sitecore.ContentSearch.ComputedFields.ReadItemRoles,Sitecore.ContentSearch</field>
</fields>

注意存储的类型是字符串的集合。我们将使用它来索引可以读取项目的所有角色名称。

执行

  1. 我们有一个基础抽象类来处理项目安全细节的提取

    public abstract class ItemPermissions: IComputedIndexField
    {
        public string FieldName { get; set; }
        public string ReturnType { get; set; }
    
        public object ComputeFieldValue(IIndexable indexable)
        {
            var indexableItem = indexable as SitecoreIndexableItem;
            if (indexableItem == null) return null;
    
            var security = indexableItem.Item.Security;
    
            return GetPermissibles(security);
        }
    
        protected abstract object GetPermissibles(ItemSecurity security);
    }
    
  2. 我们用抽象的方法来实现上面的

    public class ReadItemRoles : ItemPermissions
    {
        protected override object GetPermissibles(ItemSecurity security)
        {
            var roles = RolesInRolesManager.GetAllRoles();
            return roles.Where(security.CanRead).Select(r => r.Name);
        }
    }
    

注意这里显然会对性能产生影响,这会降低您的索引速度。为了减少影响,仅将计算字段添加到包含安全内容的索引的索引配置中。例如,如果您的 Web 内容仅由匿名用户访问,则不会带来任何好处。

管道

将条目添加到配置中

<contentSearch.getGlobalSearchFilters>
    <processor type="Sitecore.ContentSearch.Pipelines.GetGlobalFilters.ApplyGlobalReadRolesFilter, Sitecore.ContentSearch" />
  </contentSearch.getGlobalSearchFilters>

执行

实现管道过滤器以检查上下文用户的角色

public class ApplyGlobalReadRolesFilter : GetGlobalFiltersProcessor
{
    public override void Process(GetGlobalFiltersArgs args)
    {
        var query = (IQueryable<SitecoreUISearchResultItem>)args.Query;

        var userRoles = Context.User.Roles.Select(r => r.Name.Replace(@"\", @"\\"));

        var predicate = PredicateBuilder.True<SitecoreUISearchResultItem>();
        predicate = userRoles.Aggregate(predicate, (current, role) => current.Or(i => i["read_roles"].Contains(role)));

        if(predicate.Body.NodeType != ExpressionType.Constant)
            args.Query = query.Filter(predicate);
    }
}

概括

  1. 创建一个返回给定访问权限的所有有效角色列表的 ComputedField
  2. 应用管道处理器contentSearch.getGlobalSearchFilters为每个搜索请求添加查询过滤器。
  3. 使用PredicateBuilder类来确保角色名称是 OR'ed 在一起

这里最大的好处是您在索引时受到打击,并且项目限制的处理是通过搜索查询正常处理的。无需担心构面编号或搜索计数不正确。

您可以限制要检查的角色来计算字段,并且可以改变管道过滤器的应用程序。您甚至可以取出管道过滤器,并在需要时更新您的查询以进行过滤。

注意 此设置的最大问题是需要在安全限制更改时重新索引您的内容。如果您对用户本身应用安全限制,则必须包含额外的计算字段。

编辑 02/06/2013

我只是在一个项目中对此进行了修补,并意识到它正在查询中的角色。如果用户分配了多个角色,那么这两个角色都必须声明对该项目的权限。我已经更新了管道处理器以使用PredicateBuilder该类来 OR 角色。还添加了一项检查以确保谓词不是常量,这确保仅当我们有要应用的过滤器时才更新查询。

于 2013-05-22T08:19:48.550 回答
5

经过一番搜索,Linq to Sitecore文章向我指出了以下代码行:

var index = SearchManager.GetIndex("sitecore_master_index");
var context = index.CreateSearchContext(SearchSecurityOptions.EnableSecurityCheck))

通过dotPeekSitecore.ContentSearch.dll反编译器和Sitecore 7 搜索文档Sitecore.ContentSearch.LuceneProvider.dll中提到的管道,我发现了以下代码:indexing.filterIndex.outbound

Sitecore.ContentSearch.LuceneProvider.LuceneSearchReults

public IEnumerable<SearchHit<TElement>> GetSearchHits()
{
  for (int idx = this.startIndex; idx <= this.endIndex; ++idx)
  {
    Document doc = this.context.Searcher.IndexReader.Document(this.searchHits.ScoreDocs[idx].Doc, (FieldSelector) this.fieldSelector);
    if (!this.context.SecurityOptions.HasFlag((Enum) SearchSecurityOptions.DisableSecurityCheck))
    {
      string secToken = doc.GetField("_uniqueid").StringValue;
      string dataSource = doc.GetField("_datasource").StringValue;
      if (!string.IsNullOrEmpty(secToken))
      {
        bool isExcluded = OutboundIndexFilterPipeline.CheckItemSecurity(new OutboundIndexFilterArgs(secToken, dataSource));
        if (!isExcluded)
          yield return new SearchHit<TElement>(this.searchHits.ScoreDocs[idx].Score, this.configuration.IndexDocumentPropertyMapper.MapToType<TElement>(doc, this.selectMethod, this.virtualFieldProcessors, this.context.SecurityOptions));
      }
    }
    else
      yield return new SearchHit<TElement>(this.searchHits.ScoreDocs[idx].Score, this.configuration.IndexDocumentPropertyMapper.MapToType<TElement>(doc, this.selectMethod, this.virtualFieldProcessors, this.context.SecurityOptions));
  }
}

Sitecore.ContentSearch.Pipelines.IndexingFilters

public class ApplyOutboundSecurityFilter : OutboundIndexFilterProcessor
{
    public override void Process(OutboundIndexFilterArgs args)
    {
      if (args.IndexableUniqueId == null || !(args.IndexableDataSource == "Sitecore"))
        return;
      ItemUri uri = new ItemUri(args.IndexableUniqueId);
      if (args.AccessRight != AccessRight.ItemRead || Database.GetItem(uri) != null)
        return;
      args.IsExcluded = true;
    }
}

因此,看起来 Sitecore 7 使我们能够直接使用上下文用户的安全权限来过滤搜索结果,尽管它使用了与Mark Cassidy建议的非常相似的检查项目读取权限的方法。这是个好消息,因为如果这是 Sitecore 6 实施的要求,那么我们可以轻松更新 Advanced Database Crawler 来做同样的事情。

尽管如此,我仍然不相信它的性能,因为 Sitecore 7 带有物品桶和存储数百万物品的可能性。虽然应该可以创建多个索引,并且仅EnableSecurityCheck在具有启用安全性的内容的索引上,但是我们需要考虑将多个索引的结果组合起来以获得“全局搜索”结果,并考虑帐户提升,这将意味着重新排序综合结果。

于 2013-05-22T06:49:50.293 回答
2

好吧-您的考虑似乎很准确。简单的实现是通过数据库查找来检查项目 - 但是分页、分面和其他统计信息将失败。

我们所做的方法是为角色索引安全令牌 - 具有允许权限的包含字段和拒绝权限的排除字段。然后,您需要为此构建一个查询 - 并为查询展开角色中的所有角色。

您可能会遇到两个问题。一种是对角色成员资格中的所有角色进行非常复杂的 OR 查询。可能不如表现好。另一个是索引拥塞 - 因为当安全性和权限发生更改时,您需要索引内容项的主要部分,然后继承。

另一种方法是使用连接查询——但通常这会很糟糕。

于 2013-05-22T05:52:03.880 回答
0

Sitecore 开发人员犯了一个愚蠢的错误,它永远不会起作用,因为该语句: if ((args.IndexableUniqueId != null) && (args.IndexableDataSource == "Sitecore"))

因为 args.IndexableDataSource 将始终等于“sitecore”而不是“Sitecore”。我目前正在将大项目升级到最新的 7.2 更新,并发现了那个愚蠢的错误,哦 Sitecore Devs 的常见错误 :)

于 2014-09-23T11:03:54.360 回答