我定义了几个角色,每个角色对内容和媒体项都有不同的限制,我想限制根据当前登录用户的访问权限返回的搜索结果,而不是显示结果和用户然后出现“拒绝访问”页面。外网\匿名显然可以访问某些内容,因此无论如何都应该为所有用户返回它们。
安全性遵循标准Sitecore practices,因此将使用角色继承(角色中的角色),因此还需要考虑这一点。
我在Advanced Database Crawler module中看不到任何有用的内容,我查看了Sitecore搜索和索引指南(version 6.6和version 7),但找不到任何内容有关索引应用于项目的安全性的信息。以下文章有一些建议:
这感觉“很脏”并且可能会出现性能问题,尤其是在返回大量商品时。另外,(在评论中看到)分页结果的问题。
以上看起来更加真实,并且会根据索引的安全角色过滤掉结果,显然需要扩展角色来处理角色中的角色。我在这里担心的是,当我们特别需要拒绝/限制某些角色对内容项的访问时,我们需要处理被拒绝的权限(我知道这不是推荐的做法,但是有一个非常具体的需要总是拒绝)。
我正处于计划阶段,所以今天发布Sitecore 7还有可能使用更新的Lucene库和/或SOLR,如果这样可以让生活更轻松 - 当然假设有些模块例如WebForms for Marketers和Email Campaign Manager会在不久之前更新。
考虑到安全性,人们用于返回搜索结果的解决方案是什么?除上述相关问题之外的其他选择?也许我可以利用Sitecore 7中的东西,更新的Lucene库或SOLR?
我希望将这一切保持在“开箱即用”的Sitecore,如果可能的话,不要使用其他第三方搜索产品。
答案 0 :(得分:14)
克劳斯的建议略有替代:
在Sitecore.ContentSeach.config
中,您会找到一个名为contentSearch.getGlobalSearchFilters
添加到此管道的处理器将应用于任何查询,因此如果我们放入一个基于角色应用过滤器的处理器,我们就会很好。
首先,我们希望在索引配置中添加一个计算字段:
<fields hint="raw:AddComputedIndexField">
<field fieldName="read_roles" returnType="stringCollection">Sitecore.ContentSearch.ComputedFields.ReadItemRoles,Sitecore.ContentSearch</field>
</fields>
注意存储的类型是字符串的集合。我们将使用它来索引可以读取项目的角色的所有名称。
我们有一个基本抽象类来处理项目安全性详细信息的提取
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);
}
我们用抽象方法实现上述方法
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);
}
}
contentSearch.getGlobalSearchFilters
,为每个搜索请求添加查询过滤器。PredicateBuilder
类确保将角色名称组合在一起这里的一大好处是你在索引时采取命中,并且正常通过搜索查询处理项目限制。无需担心方面数字或搜索计数不正确。
您可以限制要检查的角色来计算字段,并且可以改变管道过滤器的应用程序。您甚至可以取出管道过滤器,只需更新您的查询即可在需要时进行过滤。
注意此设置的最大问题是在安全限制发生变化时需要重新编制内容索引。如果您对用户自己应用安全限制,则必须包含其他计算字段。
编辑02/06/2013
我只是在一个项目中修补它,并意识到它是在查询中的角色。如果用户分配了多个角色,则两个角色都必须具有该项的声明权限。我已经更新了管道处理器,使用PredicateBuilder
类来表示角色。还会添加一个检查以确保谓词不是常量,这样可以确保只有在我们要应用过滤器时才更新查询。
答案 1 :(得分:4)
经过一番搜索后,Linq to Sitecore文章向我指出了以下几行代码:
var index = SearchManager.GetIndex("sitecore_master_index");
var context = index.CreateSearchContext(SearchSecurityOptions.EnableSecurityCheck))
在dotPeek反编译器中挖掘Sitecore.ContentSearch.dll
和Sitecore.ContentSearch.LuceneProvider.dll
并在Sitecore 7搜索文档中提及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让我们能够直接使用上下文用户的安全权利来过滤搜索结果,尽管使用了一种非常类似的检查项目读取权限的方法{{3}建议。这是个好消息,因为如果这是Sitecore 6实现的要求,那么我们可以轻松更新高级数据库爬虫以执行相同的操作。
但是,鉴于Sitecore 7附带了Item Buckets以及存储数百万件物品的可能性,我仍然不相信它的性能。应该可以创建多个索引,并且只对具有安全性启用内容的索引进行EnableSecurityCheck
,但是我们需要考虑将来自多个索引的结果与“全局搜索”结果相结合,并考虑到Boosting将意味着重新排序合并的结果。
答案 2 :(得分:2)
我们采用的方法是为角色编制安全令牌索引 - 包含允许的包含字段和拒绝权限的排除字段。然后,您需要为此构建一个查询 - 并展开查询角色中的所有角色。
您可能面临两个问题。 一个是角色成员资格中所有角色的非常复杂的OR查询。可能会少于表现良好。 另一种是索引拥塞 - 因为当安全性和权限发生变化时,您需要索引内容项的主要部分,然后继承。
另一种方法是使用连接查询 - 但通常表现不佳。
答案 3 :(得分:0)
Sitecore开发人员犯了一个愚蠢的错误,因为该声明,它永远不会起作用: if((args.IndexableUniqueId!= null)&amp;&amp;(args.IndexableDataSource ==&#34; Sitecore&#34;))
as args.IndexableDataSource将始终等于&#34; sitecore&#34;不是&#34; Sitecore&#34;。 我目前正在将大项目升级到最新的7.2更新,发现这个愚蠢的错误,哦Sitecore Devs常见的错误:)