Seguridad

PowerPortalsPro ofrece un modelo de seguridad flexible y basado en código que te permite controlar el acceso tanto a nivel de tabla como a nivel de registro. La seguridad se implementa creando clases de manejadores de permisos y registrándolas en el contenedor de inyección de dependencias.

Resumen

Hay dos interfaces que puedes implementar dependiendo del nivel de control que necesites:

Propina

Si solo necesitas comprobaciones a nivel de tabla (por ejemplo, "los usuarios autenticados pueden leer esta tabla"), usa ITablePermissionHandler. Si necesitas lógica a nivel de registro (por ejemplo, "los usuarios solo pueden eliminar registros que poseen"), usa ITableRecordPermissionHandler.

Buenas prácticas — filtrar en la fuente

Los manejadores de permisos hacen cumplir el acceso, pero no sustituyen el filtrado. Los gestores a nivel de registro se ejecutan después de que se recupere una página de registros de Dataverse, por lo que depender de ellos para ocultar filas distorsiona la paginación de la cuadrícula (una página de 50 puede mostrar menos) y el recuento total, y desperdicia consultas recuperando filas que luego se descartan. Siempre que los datos deban asignarse al usuario actual, filtra a nivel de consulta — con una IFetchXmlQueryFilterInterceptor vista (ver más abajo) o personalizada que tenga en cuenta al usuario actual — para que Dataverse devuelva solo las filas que el usuario debería ver y cuadrícula la página correctamente. Mantén a los responsables de permisos como garantía de cumplimiento.

Dataverse-Native Security (Vista previa)

El modelo de seguridad recomendado para el futuro permite que Dataverse imponga la seguridad para los usuarios de tu portal, basado en la función unificada de seguridad Dataverse de Power Pages. En lugar de escribir manejadores de permisos en código, gestionas el acceso con roles de seguridad estándar de Dataverse — los mismos roles, privilegios y herramientas administrativas que se usan para los usuarios internos. El modelo está actualmente en vista previa — tanto la función de Microsoft como el soporte de Power Portals Pro — y Power Portals Pro seguirá el calendario de lanzamientos de Microsoft hasta la disponibilidad general.

Cuando está habilitado, PowerPortalsPro provisiona automáticamente un sistema gestionado por el sistema (C2) systemuser para cada contacto del portal — al registrarse para nuevos contactos y de forma perezosa al iniciar sesión para los existentes — junto con el powerpagesusermapping registro que vincula el contacto, el usuario del sistema y tu sitio Power Pages. Cada llamada de Dataverse para la sesión se hace pasar por ese usuario del sistema, por lo que los roles de seguridad que Power Pages sincroniza desde tus permisos web de roles y tablas gobiernan exactamente lo que el usuario puede ver y hacer. La sesión lleva un PortalUserType de ContactStubUser para que tu interfaz siempre pueda distinguir a estos usuarios provisionados de los usuarios internos reales.

Nota

Para usar este modelo de seguridad debes crear un sitio web de Power Pages en tu entorno Dataverse — esto es lo que instala los componentes del framework de Microsoft y te permite activar la función de seguridad unificada. No necesitas un plan de pago de PowerPages, y puedes eliminar la web inmediatamente después de instalar y activar la función. El registro del sitio de Power Pages (powerpagesite) al que PowerPagesSiteId se refiere debe existir en el entorno, ya que los mapeos de usuario y la sincronización de seguridad-rol se resuelven en su contra.

Habilitación de la seguridad nativa de Dataverse

Activa el modelo desde SecurityOptions el Program.csservidor , proporcionando el id del registro de tu sitio de Power Pages:

La configuración se valida al iniciar la aplicación: cuando ProvisionSystemUsers está habilitada, PowerPagesSiteId debe establecerse y debe resolverse a un registro existente powerpagesite , de lo contrario la aplicación no arranca con guía.

Concede acceso exactamente como lo hace Power Pages: configura los roles web y permisos de las tablas en la app Power Pages Management, y asigna roles web a los contactos (a través de la app Management o de forma programática). La plataforma sincroniza esos roles de seguridad generados automáticamente (llamados PowerPages_*) y los asigna automáticamente como cambios de membresía en el rol web — como la configuración está completamente en Power Pages, tu portal puede moverse hacia o desde un sitio real de Power Pages sin fricciones. Ten en cuenta que los cambios de roles y privilegios pueden tardar desde unos segundos hasta un par de minutos en propagarse a través de las cachés de Dataverse antes de hacer efecto.

Sigue la guía paso a paso de configuración

Empezando

1. Crear un gestor de permisos

Crea una clase que implemente ITablePermissionHandler o ITableRecordPermissionHandler. Establece la Table propiedad en el nombre lógico de la tabla Dataverse a la que se aplica el manejador e implementa cada método de permisos.

Aquí tienes un ejemplo sencillo que otorga acceso completo a todos los usuarios para una tabla específica:

2. Registrar en la inyección de dependencias

Registra tu manejador en el contenedor DI del archivo de Program.cs tu proyecto (o en un método de extensión de colección de servicios):

Dado que los manejadores se resuelven desde el contenedor DI, puedes inyectar cualquier servicio requerido (como un contexto de base de datos o un servicio de usuario) mediante inyección de constructores.

Seguridad a nivel de récord

Para escenarios en los que el acceso depende del registro específico en el que se está operando, implementa ITableRecordPermissionHandler. Esta interfaz se extiende ITablePermissionHandler con sobrecargas que reciben el TableRecord.

El siguiente ejemplo permite a todos los usuarios leer registros globalmente, pero restringe las operaciones de escritura a los registros propiedad del usuario actual:

Nota

La CanUpdateAsync sobrecarga a nivel de registro proporciona tanto al registro las actualizaciones propuestas (recordWithUpdates) como al registro en su estado persistido actual (currentRecord), lo que permite comparar valores o validar cambios específicos en el campo.

Columnas requeridas

La RequiredColumns propiedad especifica qué columnas deben recuperarse para que el manejador evalúe permisos a nivel de registro. El framework añade automáticamente estas columnas a las consultas FetchXML cuando no están ya incluidas, asegurando que el gestor siempre tenga los datos que necesita — incluso si la vista o consulta no incluye esas columnas.

El siguiente ejemplo utiliza la ppp_owningportaluserid columna de búsqueda para restringir el acceso a registros propiedad del usuario actual:

Nota

Si RequiredColumns devuelve una lista vacía y los métodos a nivel de registro del manejador solo usan record.Id, no se añaden columnas adicionales a la consulta. La owner propiedad siempre es proporcionada por la plataforma, independientemente de RequiredColumns.

Interceptores de filtro de consulta FetchXML

Además de la seguridad a nivel de tabla y registro, PowerPortalsPro soporta IFetchXmlQueryFilterInterceptor — una interfaz que permite modificar consultas FetchXML antes de que se ejecuten. Esto es útil para hacer cumplir el filtrado a nivel de fila, como asegurar que un usuario solo pueda ver los registros que le pertenecen a él o a su equipo.

IFetchXmlQueryFilterInterceptor extiende ITablePermissionHandler, por lo que cada interceptor también define permisos a nivel de tabla mediante la Table propiedad y los métodos de permisos estándar. El método del OnQueryAsync interceptor solo se llama para consultas que se dirigen a su tabla especificada.

A diferencia de los gestores de permisos a nivel de registro que evalúan cada registro tras la recuperación, los interceptores de filtro de consulta modifican la consulta antes de que llegue a Dataverse. Los registros filtrados nunca se recuperan, lo que mejora el rendimiento y la seguridad — y, lo que es importante, mantiene la paginación en cuadrícula y los conteos totales precisos, ya que el filtrado aplicado tras la recuperación dejaría las páginas cortas y contaría mal los totales.

1. Crear un interceptor de filtro de consulta

Implementa IFetchXmlQueryFilterInterceptor, establece la Table propiedad al nombre lógico de la tabla, implementa los métodos de permisos y usa el FetchXMLBuilder in OnQueryAsync para añadir filtros a la consulta. El FetchXmlParameters registro proporciona el archivo del usuario EntityReferenceactual FetchXMLBuilder

El siguiente ejemplo restringe las consultas en la contact tabla para que solo devuelvan el registro que coincide con el usuario actual:

2. Registrar en la inyección de dependencias

Registra tu interceptor tanto como un IFetchXmlQueryFilterInterceptor como ITablePermissionHandler un para que se apliquen tanto el filtrado de consultas como los permisos a nivel de tabla. Se pueden registrar múltiples interceptores y cada uno se ejecutará para consultas dirigidas a su tabla.

Propina

Porque IFetchXmlQueryFilterInterceptor extiende ITablePermissionHandler, una sola clase gestiona tanto permisos a nivel de tabla como filtrado a nivel de consulta. El OnQueryAsync método solo se invoca para consultas que coinciden con la propiedad del Table interceptor, por lo que no es necesario comprobar el nombre de la tabla dentro del método.

Clases base integradas

El marco proporciona clases base para simplificar patrones de seguridad comunes:

Referencia API

ITablePermissionHandler Interface

Propiedades

Nombre
Tipo
Default
Descripción
Tablestring
Nombre lógico de la tabla a la que se aplica este manejador de permisos.
Nombre: Table
Tipo: string
Descripción: Nombre lógico de la tabla a la que se aplica este manejador de permisos.

Métodos

Nombre
Parámetros
Tipo
Descripción
CanAppendAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debería poder añadir un registro.
CanAppendToAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debe poder añadir a un registro.
CanCreateAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debe ser capaz de crear un registro.
CanDeleteAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debería poder eliminar un registro.
CanReadAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debería ser capaz de leer un registro.
CanUpdateAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debe poder actualizar un registro.
Nombre: CanAppendAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debería poder añadir un registro.
Nombre: CanAppendToAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe poder añadir a un registro.
Nombre: CanCreateAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe ser capaz de crear un registro.
Nombre: CanDeleteAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debería poder eliminar un registro.
Nombre: CanReadAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debería ser capaz de leer un registro.
Nombre: CanUpdateAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe poder actualizar un registro.

ITableRecordPermissionHandler Interface

Propiedades

Nombre
Tipo
Default
Descripción
RequiredColumnsList<string>
Lista de nombres lógicos de columnas que deben recuperarse para que este manejador pueda evaluar permisos a nivel de registro.
Tablestring
Nombre lógico de la tabla a la que se aplica este manejador de permisos.
Nombre: RequiredColumns
Tipo: List<string>
Descripción: Lista de nombres lógicos de columnas que deben recuperarse para que este manejador pueda evaluar permisos a nivel de registro.
Nombre: Table
Tipo: string
Descripción: Nombre lógico de la tabla a la que se aplica este manejador de permisos.

Métodos

Nombre
Parámetros
Tipo
Descripción
CanAppendAsyncGuid? userId
TableRecord record
Task<bool>
Método para determinar si un usuario debe poder añadir el registro proporcionado.
CanAppendToAsyncGuid? userId
TableRecord record
Task<bool>
Método para determinar si un usuario debe poder añadir al registro proporcionado.
CanCreateAsyncGuid? userId
TableRecord record
Task<bool>
Método para determinar si un usuario debe poder crear el registro proporcionado.
CanDeleteAsyncGuid? userId
TableRecord record
Task<bool>
Método para determinar si un usuario debe poder eliminar el registro proporcionado.
CanReadAsyncGuid? userId
TableRecord record
Task<bool>
Método para determinar si un usuario debe poder leer el registro proporcionado.
CanUpdateAsyncGuid? userId
TableRecord recordWithUpdates
TableRecord currentRecord
Task<bool>
Método para determinar si un usuario debe poder actualizar el registro proporcionado.
Nombre: CanAppendAsync
Parámetros: Guid? userId
TableRecord record
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe poder añadir el registro proporcionado.
Nombre: CanAppendToAsync
Parámetros: Guid? userId
TableRecord record
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe poder añadir al registro proporcionado.
Nombre: CanCreateAsync
Parámetros: Guid? userId
TableRecord record
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe poder crear el registro proporcionado.
Nombre: CanDeleteAsync
Parámetros: Guid? userId
TableRecord record
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe poder eliminar el registro proporcionado.
Nombre: CanReadAsync
Parámetros: Guid? userId
TableRecord record
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe poder leer el registro proporcionado.
Nombre: CanUpdateAsync
Parámetros: Guid? userId
TableRecord recordWithUpdates
TableRecord currentRecord
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe poder actualizar el registro proporcionado.

IFetchXmlQueryFilterInterceptor Interface

Propiedades

Nombre
Tipo
Default
Descripción
Tablestring
Nombre lógico de la tabla a la que se aplica este manejador de permisos.
Nombre: Table
Tipo: string
Descripción: Nombre lógico de la tabla a la que se aplica este manejador de permisos.

Métodos

Nombre
Parámetros
Tipo
Descripción
CanAppendAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debería poder añadir un registro.
CanAppendToAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debe poder añadir a un registro.
CanCreateAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debe ser capaz de crear un registro.
CanDeleteAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debería poder eliminar un registro.
CanReadAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debería ser capaz de leer un registro.
CanUpdateAsyncGuid? userId
Task<bool>
Método para determinar si un usuario debe poder actualizar un registro.
OnQueryAsyncFetchXMLBuilder fetchXmlBuilder
FetchXmlParameters parameters
Task<FetchXMLBuilder>
Se llama para permitir la modificación de una consulta FetchXML antes de que se ejecute.
Nombre: CanAppendAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debería poder añadir un registro.
Nombre: CanAppendToAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe poder añadir a un registro.
Nombre: CanCreateAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe ser capaz de crear un registro.
Nombre: CanDeleteAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debería poder eliminar un registro.
Nombre: CanReadAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debería ser capaz de leer un registro.
Nombre: CanUpdateAsync
Parámetros: Guid? userId
Tipo: Task<bool>
Descripción: Método para determinar si un usuario debe poder actualizar un registro.
Nombre: OnQueryAsync
Parámetros: FetchXMLBuilder fetchXmlBuilder
FetchXmlParameters parameters
Tipo: Task<FetchXMLBuilder>
Descripción: Se llama para permitir la modificación de una consulta FetchXML antes de que se ejecute.