Verificando el acceso en código

El único momento en el que no debería preocuparse por los conceptos de seguridad es cuando está escribiendo código que ejecuta un usuario con rol de seguridad Administrador del sistema. Dado que este rol lo abarca todo y no se puede editar, puede estar seguro de que el usuario puede hacer cualquier cosa. En todos los demás casos, debe considerar cómo se aplica la seguridad.

  • Si está creando un aplicación cliente, debe evaluar los privilegios del usuario para una tabla o para un registro de tabla específico y controlar qué comandos habilita. Si un usuario no puede crear una tabla, puede deshabilitar la interfaz de usuario en su aplicación para permitir la creación de una nueva tabla de ese tipo. Si no tienen acceso de lectura a una tabla, su aplicación cliente puede optar por no mostrar los componentes relacionados con la visualización de listas de ese tipo de tabla.

  • Si está escribiendo un complemento sincrónico, no puede intentar alguna operación de datos y descartar la excepción. Cualquier operación que falle dentro de un complemento síncrono hará que se revierta toda la transacción de datos. Si alguna parte del proceso es opcional según los privilegios del usuario, primero debe verificar los privilegios del usuario.

Hay dos estrategias que puede aplicar para detectar qué operaciones puede realizar un usuario:

  • Probar registros de tabla individuales
  • Verificar los privilegios de seguridad del usuario

Estas estrategias se describen a continuación.

Probar registros de tabla individuales

La interacción del usuario con registros de tablas específicos generalmente comienza con una consulta. Si un usuario no tiene acceso a ningún registro para esa tabla, la consulta no devolverá ningún registro y no hay nada más que el usuario pueda intentar excepto crear un nuevo registro. Probar si el usuario puede crear un nuevo registro requiere usar la otra estrategia (mencionada anteriormente) para verificar los privilegios de seguridad del usuario.

Sin embargo, si el usuario logró recuperar los registros de la tabla mediante una consulta, puede probar un registro mediante el mensaje RetrievePrincipalAccess.

El siguiente método estático GetAccessRights utiliza el SDK Clase RetrievePrincipalAccessRequestRetrievePrincipalAccessRequest para recuperar un conjunto de derechos de acceso que un usuario, equipo u organización tiene para un registro usando la Enumeración AccessRights.

/// <summary>
/// Gets which access rights a user, team, or organization has for a specific record.
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="userOrTeamOrOrganization">The user, team, or organization to check</param>
/// <param name="entity">A reference to the entity to check.</param>
/// <returns>The access rights the user can perform.</returns>
static AccessRights GetAccessRights(
        IOrganizationService service,
        EntityReference userOrTeamOrOrganization,
        EntityReference entity)
{
    var request = new RetrievePrincipalAccessRequest()
    {
        Principal = userOrTeamOrOrganization,
        Target = entity
    };

    var response = (RetrievePrincipalAccessResponse)service.Execute(request);

    return response.AccessRights;
}

Con el valor recuperado por este método, puede utilizar el Método Enum.HasFlag para devolver un valor booleano cuando el usuario tiene acceso para realizar operaciones específicas en la tabla.

El siguiente fragmento de código muestra cómo usar el método estático GetAccessRights para probar si un usuario tiene acceso para anexar registros a un registro de cuenta usando el miembro AppendToAccess.

var whoIAm = (WhoAmIResponse)service.Execute(new WhoAmIRequest());

var meRef = new EntityReference("systemuser", whoIAm.UserId);

QueryExpression query = new("account") { 
        ColumnSet = new ColumnSet("accountid"),
        TopCount = 1
};

EntityCollection accounts = service.RetrieveMultiple(query);

EntityReference accountRef = accounts
    .Entities
    .FirstOrDefault()
    .ToEntityReference();

AccessRights rights = GetAccessRights(service, meRef, accountRef);

var canAppendTo = rights.HasFlag(AccessRights.AppendToAccess);

Con acceso a un registro de tabla, puede utilizar los derechos de acceso devueltos para probar cualquier operación que se aplique a ese registro. Pero esta prueba no incluye las capacidades que se aplican a otras operaciones, como la creación de un nuevo registro o cualquier otro privilegio que no esté vinculado a una tabla específica. Para estas operaciones, debe Comprobar los privilegios de seguridad de un usuario.

Conseguir entidades de seguridad con acceso a un registro

Algunas operaciones de datos requieren que otro usuario tenga acceso a un registro. Si solo cuenta con un usuario, equipo u organización, puede probar el otro usuario usando el mensaje RetrievePrincipalAccess.

Sin embargo, si necesita una lista de todos los usuarios, equipos u organizaciones con los que se ha compartido un registro, utilice el mensaje RetrieveSharedPrincipalsAndAccess. RetrieveSharedPrincipalsAndAccess proporciona detalles sobre los derechos de acceso que tiene cada usuario, equipo u organización porque el registro se compartió con ellos.

El siguiente método estático GetSharedPrincipalsAndAccess utiliza las clases RetrieveSharedPrincipalsAndAccessRequest y RetrieveSharedPrincipalsAndAccessResponse para devolver una matriz de datos PrincipalAccess con detalles sobre las entidades de seguridad y el acceso que tienen porque el registro fue compartido con ellos.

/// <summary>
/// Returns details about access principals have because a record was shared with them.
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="target">The record to check</param>
/// <returns>The principal access data for each user, team, or organization</returns>
static PrincipalAccess[] GetSharedPrincipalsAndAccess(
    IOrganizationService service,
    EntityReference target)
{
    var request = new RetrieveSharedPrincipalsAndAccessRequest()
    {
        Target = target
    };

    var response = (RetrieveSharedPrincipalsAndAccessResponse)service.Execute(request);

    return response.PrincipalAccesses;
}

Verificar los privilegios de seguridad de un usuario

Cuando no tiene un registro de tabla específico para probar, como si un usuario puede crear un nuevo registro de tabla, debe confiar en verificar los privilegios de seguridad del usuario. Estos privilegios se almacenan en la tabla Privilegio.

Hay casi 1000 privilegios individuales en la base de datos de Dataverse y el número aumenta con cada tabla que se agregue al sistema. Puede recuperar una lista de los privilegios disponibles en su ambiente ejecutando la siguiente FetchXML consulta.

<fetch version='1.0' distinct='true' no-lock='true' >
  <entity name='privilege' >
    <attribute name='name' />
  </entity>
</fetch>

Sugerencia

El Generador FetchXML XrmToolBox es una herramienta útil para componer y probar FetchXML consultas.

El valor del atributo name sigue este patrón de convención de nomenclatura cuando el privilegio se aplica a tablas: "prv + Verbo + SchemaName de tabla". El verbo puede ser Anexar, Anexar a, asignar, Crear, Eliminar, Compartir, Escribir.

Además de los privilegios para las tablas, hay menos de 100 privilegios especiales que no están asociados con las tablas. Puede usar la siguiente consulta para recuperar estos privilegios.

<fetch version='1.0' distinct='true' no-lock='true' >

<entity name='privilege' >
  <attribute name='name' />
  <filter>
    <condition attribute='name' operator='not-begin-with' value='prvAppend' />
    <condition attribute='name' operator='not-begin-with' value='prvAssign' />
    <condition attribute='name' operator='not-begin-with' value='prvCreate' />
    <condition attribute='name' operator='not-begin-with' value='prvDelete' />
    <condition attribute='name' operator='not-begin-with' value='prvRead' />
    <condition attribute='name' operator='not-begin-with' value='prvShare' />
    <condition attribute='name' operator='not-begin-with' value='prvWrite' />
  </filter>
</entity>

</fetch>

Utilice estos mensajes para recuperar privilegios por Id. de privilegio o nombre. Incluyen privilegios que el usuario puede tener de los equipos.

Publicación Función de la API web
Solicitud de clase SDK
RetrieveUserPrivilegeByPrivilegeId Función RetrieveUserPrivilegeByPrivilegeId
Clase RetrieveUserPrivilegeByPrivilegeIdRequest
RetrieveUserPrivilegeByPrivilegeName Función RetrieveUserPrivilegeByPrivilegeName
Clase RetrieveUserPrivilegeByPrivilegeNameRequest
RetrieveUserSetOfPrivilegesByIds Función RetrieveUserSetOfPrivilegesByIds
Clase RetrieveUserSetOfPrivilegesByIdsRequest
RetrieveUserSetOfPrivilegesByNames Función RetrieveUserSetOfPrivilegesByNames
Clase RetrieveUserSetOfPrivilegesByNamesRequest

Ejemplo: comprobar si un usuario tiene un privilegio

Los siguientes ejemplos muestran el uso del mensaje RetrieveUserPrivilegeByPrivilegeName. Este mensaje recupera la lista de privilegios para un usuario del sistema (usuario) de todos los roles directos asociados con el usuario del sistema y de todos los roles indirectos asociados con los equipos de los que el usuario del sistema es miembro en función del nombre de privilegio especificado.

El siguiente método estático HasPrivilege devuelve si el usuario tiene el privilegio nombrado.

/// <summary>
/// Returns whether specified user has a named privilege
/// </summary>
/// <param name="service">The IOrganizationService instance to use.</param>
/// <param name="systemUserId">The Id of the user.</param>
/// <param name="privilegeName">The name of the privilege.</param>
/// <returns></returns>
static bool HasPrivilege(IOrganizationService service,
        Guid systemUserId,
        string privilegeName)
{
    var request = new
        RetrieveUserPrivilegeByPrivilegeNameRequest
    {
        PrivilegeName = privilegeName,
        UserId = systemUserId
    };
    var response =
        (RetrieveUserPrivilegeByPrivilegeNameResponse)service
        .Execute(request);
    if (response.RolePrivileges.Length > 0)
    {
        return true;
    }
    return false;
}

Más información:

Recuperar los privilegios para un rol de seguridad

Puede recuperar los privilegios asociados con un rol de seguridad.

El siguiente método estático GetRolePrivileges recupera los privilegios asociados con un rol.

/// <summary>
/// Retrieves the privileges for a role.
/// </summary>
/// <param name="service">Authenticated client implementing the IOrganizationService interface</param>
/// <param name="roleId">The id of the role</param>
/// <returns>Privilege records associated to the role</returns>
static EntityCollection GetRolePrivileges(IOrganizationService service, Guid roleId) {

    Relationship roleprivileges_association = new("roleprivileges_association");

    var relationshipQueryCollection = new RelationshipQueryCollection();

    var relatedPrivileges = new QueryExpression("privilege")
    {
        ColumnSet = new ColumnSet("name")
    };

    relationshipQueryCollection.Add(roleprivileges_association, relatedPrivileges);

    var request = new RetrieveRequest()
    {
        ColumnSet = new ColumnSet(true),
        RelatedEntitiesQuery = relationshipQueryCollection,
        Target = new EntityReference("role", roleId)
    };

    var response = (RetrieveResponse)service.Execute(request);

    return response.Entity.RelatedEntities[roleprivileges_association];
}

Más información: Recuperar con filas relacionadas

Consulte también

Complementos

Nota

¿Puede indicarnos sus preferencias de idioma de documentación? Realice una breve encuesta. (tenga en cuenta que esta encuesta está en inglés)

La encuesta durará unos siete minutos. No se recopilan datos personales (declaración de privacidad).