security - tag - Indexar la seguridad del elemento de Sitecore y restringir los resultados de búsqueda devueltos
robots.txt no index (4)
Después de buscar más, el artículo de Linq to Sitecore me indicó las siguientes líneas de código:
var index = SearchManager.GetIndex("sitecore_master_index");
var context = index.CreateSearchContext(SearchSecurityOptions.EnableSecurityCheck))
Excavando a través de Sitecore.ContentSearch.dll
y Sitecore.ContentSearch.LuceneProvider.dll
en descompilador dotPeek y la mención de indexing.filterIndex.outbound
pipeline en el documento de búsqueda de Sitecore 7 encontré el siguiente código:
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;
}
}
Así que parece que Sitecore 7 nos da la capacidad de filtrar los resultados de búsqueda utilizando los derechos de seguridad del usuario de contexto directamente, aunque con un método muy similar de comprobación de los permisos de lectura de elementos que Mark Cassidy sugirió. Lo cual es una buena noticia, ya que si este es un requisito para las implementaciones de Sitecore 6, podemos actualizar fácilmente el rastreador de base de datos avanzado para hacer lo mismo.
Sin embargo, todavía no estoy convencido del rendimiento de esto, dado que Sitecore 7 viene con Cubos de artículos y la posibilidad de almacenar millones de artículos. Sin embargo, debería ser posible crear varios índices y solo EnableSecurityCheck
en índices con contenido habilitado para seguridad, pero luego debemos pensar en combinar los resultados de varios índices para obtener resultados de "búsqueda global" y también en el aumento de cuentas, lo que significará ordenando los resultados combinados.
Tengo varios roles definidos, cada uno con diferentes restricciones para el contenido y los elementos multimedia, y me gustaría restringir los resultados de búsqueda que se devuelven en función de los derechos de acceso del usuario actualmente conectado, en lugar de mostrar el resultado y luego el usuario presenta una página "Acceso denegado". Cierta cantidad de contenido obviamente estará disponible para la extranet / anonymous, por lo que deben devolverse para todos los usuarios independientemente.
La seguridad sigue las prácticas estándar de Sitecore , por lo que se usará la herencia de rol (roles dentro de los roles), por lo que deberá tener esto en cuenta también.
No pude ver nada en el módulo del rastreador de la base de datos avanzada que ayudaría y revisé la Búsqueda de Sitecore y la Guía de indización ( versión 6.6 y la versión 7 ) pero no pude encontrar información sobre la indexación de la seguridad aplicada a los elementos. Los siguientes artículos tienen algunas sugerencias:
Esto se siente "sucio" y tiene el potencial de problemas de rendimiento, especialmente cuando hay una gran cantidad de artículos devueltos. Además, (ver en los comentarios) el problema con los resultados de búsqueda.
Lo anterior parece más realista y filtrar los resultados en función de las funciones de seguridad indexadas, obviamente, sería necesario ampliar los roles para manejar las funciones dentro de los roles. Mi preocupación aquí sería que tendríamos que manejar los permisos denegados, cuando específicamente necesitamos denegar / restringir el acceso de ciertos elementos a los elementos de contenido (sé que esto no es una práctica recomendada, pero hay una necesidad muy específica de denegar siempre).
Estoy en la etapa de planificación en este momento, así que con el lanzamiento de Sitecore 7 hoy también existe la posibilidad de utilizar las bibliotecas actualizadas de Lucene y / o SOLR si eso hace la vida más fácil, asumiendo por supuesto que algunos de los módulos como WebForms para Los marketers y el administrador de la campaña de correo electrónico se actualizan en poco tiempo.
¿Cuáles son las soluciones que las personas están usando para devolver los resultados de búsqueda teniendo en cuenta la seguridad? ¿Alguna alternativa a las preguntas vinculadas anteriores? ¿Tal vez algo en Sitecore 7 que pueda aprovechar, las bibliotecas actualizadas de Lucene o SOLR?
Preferiría mantener todo esto fuera de la caja de Sitecore y no utilizar otros productos de búsqueda de terceros si es posible.
Los desarrolladores de Sitecore cometieron un error tonto, nunca funcionará, debido a esa declaración: if ((args.IndexableUniqueId! = Null) && (args.IndexableDataSource == "Sitecore"))
como args.IndexableDataSource siempre será igual a "sitecore" no "Sitecore". Actualmente estoy actualizando un gran proyecto a la última actualización de 7.2 y descubrí ese error tonto, oh errores habituales de Sitecore Devs :)
Una ligera alternativa a la sugerencia de Klaus:
En Sitecore.ContentSeach.config
encontrará una canalización llamada contentSearch.getGlobalSearchFilters
Los procesadores agregados a esta canalización se aplicarán a cualquier consulta, por lo que si incluimos uno que aplique un filtro basado en roles, estamos bien.
ComputedField
Para comenzar, queremos agregar un campo calculado a nuestra configuración de índice:
<fields hint="raw:AddComputedIndexField">
<field fieldName="read_roles" returnType="stringCollection">Sitecore.ContentSearch.ComputedFields.ReadItemRoles,Sitecore.ContentSearch</field>
</fields>
NOTE que el tipo almacenado es una colección de cadenas. Lo usaremos para indexar todos los nombres de roles que pueden leer un elemento.
Implementación
Tenemos una clase abstracta base para manejar la extracción de detalles de seguridad del artículo
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); }
Implementamos lo anterior con el método abstracto
public class ReadItemRoles : ItemPermissions { protected override object GetPermissibles(ItemSecurity security) { var roles = RolesInRolesManager.GetAllRoles(); return roles.Where(security.CanRead).Select(r => r.Name); } }
NOTA Obviamente, hay un impacto en el rendimiento aquí, esto reducirá su velocidad de indexación. Para reducir el impacto, solo agregue el campo calculado a la configuración de índice para el índice que contiene contenido protegido. Por ejemplo, si el usuario anónimo solo accede a su contenido web, no agregará ningún beneficio.
Tubería
Agregue la entrada a la configuración
<contentSearch.getGlobalSearchFilters>
<processor type="Sitecore.ContentSearch.Pipelines.GetGlobalFilters.ApplyGlobalReadRolesFilter, Sitecore.ContentSearch" />
</contentSearch.getGlobalSearchFilters>
Implementación
Implementar el filtro de canalización para verificar los roles del usuario de contexto
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);
}
}
Resumen
- Cree un campo computed que devuelva una lista de todas las funciones válidas para un derecho de acceso dado
- Aplique un procesador de canalización a
contentSearch.getGlobalSearchFilters
para agregar un filtro de consulta a cada solicitud de búsqueda. - Utilice la clase
PredicateBuilder
para asegurarse de que los nombres de los roles estén OR ''unidos
El gran beneficio aquí es que toma el golpe en el tiempo de indexación y el manejo de la restricción del elemento se maneja a través de una consulta de búsqueda de forma normal. No hay necesidad de preocuparse por los números de las facetas o los recuentos de búsqueda que son incorrectos.
Puede restringir las funciones que está verificando para calcular el campo y puede variar la aplicación del filtro de canalización. Incluso puede eliminar el filtro de canalización y simplemente actualizar sus consultas para filtrar cuando lo necesite.
NOTA El mayor problema con esta configuración es el requisito de volver a indexar su contenido cuando cambian las restricciones de seguridad. Si aplica restricciones de seguridad a los usuarios, deberá incluir campos computados adicionales.
Editar 02/06/2013
Estaba retocando esto en un proyecto y me di cuenta de que era AND ''los roles en la consulta. Si un usuario tenía múltiples roles asignados, ambos roles tendrían que tener derechos declarados para el elemento. Actualicé el procesador de canalización para usar la clase PredicateBuilder
en O los roles. También se agrega una verificación para garantizar que el predicado no sea una constante, esto garantiza que la consulta se actualice solo si tenemos un filtro para aplicar.
bueno, tus consideraciones parecen estar en el objetivo. La implementación fácil es verificar el artículo a través de la búsqueda en la base de datos, pero la búsqueda, la facetación y otras estadísticas fallarán en eso.
El enfoque que hacemos es indexar los tokens de seguridad para las funciones, con un campo de inclusión para permitir y un campo de exclusión para los derechos de denegación. Luego debe crear una consulta para esto y expandir todos los roles en los roles para la consulta.
Hay dos problemas que podría enfrentar. Uno es muy complejo O pregunta por todos los roles en los roles membresías. Puede ser menos exitoso. El otro es la congestión de indexación, ya que será necesario indexar las partes principales de los elementos de contenido cuando la seguridad y los permisos cambian a medida que se heredan.
La alternativa es usar consultas de combinación, pero normalmente sería un mal rendimiento.