Verificando o acesso no código

A única vez que você não precisa se preocupar com os conceitos de segurança é quando você está escrevendo código que um usuário com a função de segurança administrador do sistema executa. Como essa função é toda poderosa e não pode ser editada, você pode ter certeza de que o usuário pode fazer qualquer coisa. Em todos os outros casos, você precisa considerar como a segurança é aplicada.

  • Se você estiver criando um aplicativo cliente, deverá avaliar os privilégios do usuário para uma tabela ou para um registro de tabela específico e controlar quais comandos você habilita. Se um usuário não tiver permissão para criar uma tabela, você poderá desabilitar a interface do usuário em seu aplicativo para permitir a criação de uma nova tabela desse tipo. Se eles não tiverem acesso de leitura a uma tabela, seu aplicativo cliente poderá optar por não exibir componentes relacionados à exibição de listas desse tipo de tabela.

  • Se você estiver escrevendo um plug-in síncrono, não poderá tentar executar alguma operação de dados e ignorar a exceção. Qualquer operação que falha em um plug-in síncrono faz com que toda a transação de dados seja revertida. Se você tiver alguma parte do processo opcional, dependendo dos privilégios do usuário, verifique primeiro os privilégios do usuário.

Há duas estratégias que você pode aplicar para detectar quais operações um usuário pode executar:

  • Testar registros individuais da tabela
  • Verificar os privilégios de segurança do usuário

Essas estratégias são descritas abaixo.

Testar registros individuais da tabela

A interação do usuário com registros de tabela específicos geralmente começa com uma consulta. Se um usuário não tiver acesso a nenhum registro para essa tabela, a consulta não retornará nenhum registro e não haverá mais nada que o usuário possa tentar, exceto criar um novo registro. Testar se o usuário pode criar um novo registro requer o uso da outra estratégia (mencionada acima) para verificar os privilégios de segurança do usuário.

No entanto, se o usuário tiver sido bem-sucedido na recuperação de registros de tabela usando uma consulta, você poderá testar um registro usando a RetrievePrincipalAccess mensagem.

GetAccessRights O método estático a seguir usa a classe SDK RetrievePrincipalAccessRequest para recuperar um conjunto de direitos de acesso que um usuário, equipe ou organização tem para um registro usando a Enumeração 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;
}

Com o valor retornado por esse método, você pode usar o Método Enum.HasFlag para retornar um valor booliano quando o usuário tiver acesso para executar operações específicas na tabela.

O snippet de código a seguir mostra como usar o GetAccessRights método estático para testar se um usuário tem acesso para acrescentar registros a um registro de conta usando o AppendToAccess membro.

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);

Com o acesso a um registro de tabela, você pode usar os direitos de acesso retornados para testar todas as operações que se aplicam a esse registro. Mas esse teste não inclui recursos que se aplicam a outras operações, como a criação de um novo registro ou qualquer outro privilégio que não esteja associado a uma tabela específica. Para essas operações, você precisa verificar os privilégios de segurança de um usuário.

Obter principais com acesso a um registro

Algumas operações de dados exigem que outro usuário tenha acesso a um registro. Se você tiver apenas um usuário, equipe ou organização específico, poderá testar usando a RetrievePrincipalAccess mensagem.

No entanto, se você precisar de uma lista de todos os usuários, equipes ou organizações com as quais um registro foi compartilhado, use a RetrieveSharedPrincipalsAndAccess mensagem. RetrieveSharedPrincipalsAndAccess fornece detalhes sobre os direitos de acesso que cada usuário, equipe ou organização tem porque o registro foi compartilhado com eles.

GetSharedPrincipalsAndAccess O método estático a seguir usa as classes RetrieveSharedPrincipalsAndAccessRequest e RetrieveSharedPrincipalsAndAccessResponse para retornar uma matriz de PrincipalAccess com detalhes sobre as entidades de segurança e o acesso que elas têm devido ao compartilhamento do registro com elas.

/// <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 os privilégios de segurança de um usuário

Quando você não tem um registro de tabela específico para testar, como se um usuário pode criar um novo registro de tabela, você deve contar com a verificação dos privilégios de segurança do usuário. Esses privilégios são armazenados na tabela Privilege.

Há quase 1.000 privilégios individuais no banco de dados do Dataverse e o número cresce a cada tabela adicionada ao sistema. Você pode recuperar uma lista dos privilégios disponíveis em seu ambiente executando a seguinte consulta FetchXML.

<fetch distinct='true' >
  <entity name='privilege' >
    <attribute name='name' />
  </entity>
</fetch>

Dica

O Construtor FetchXML do XrmToolBox é uma ferramenta útil para redigir e testar consultas FetchXML.

O valor do name atributo segue esse padrão de convenção de nomenclatura quando o privilégio se aplica a tabelas: "prv+Verb+Table SchemaName". O verbo é um de Append, AppendTo, Assign, Create, Delete, Share, Write.

Além dos privilégios relativos a tabelas, há menos de 100 outros privilégios especiais que não estão associados a tabelas. Você pode usar a consulta a seguir para recuperar esses privilégios.

<fetch distinct='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>

Use essas mensagens para recuperar privilégios por ID de privilégio ou nome. Eles incluem privilégios que o usuário pode ter das equipes.

Mensagem Função de API Web
Classe de solicitação do SDK
RetrieveUserPrivilegeByPrivilegeId Função RetrieveUserPrivilegeByPrivilegeId
Classe RetrieveUserPrivilegeByPrivilegeIdRequest
RetrieveUserPrivilegeByPrivilegeName RetrieveUserPrivilegeByPrivilegeName Function
Classe RetrieveUserPrivilegeByPrivilegeNameRequest
RetrieveUserSetOfPrivilegesByIds Função RetrieveUserSetOfPrivilegesByIds
Classe RetrieveUserSetOfPrivilegesByIdsRequest
RetrieveUserSetOfPrivilegesByNames Função RetrieveUserSetOfPrivilegesByNames
Classe RetrieveUserSetOfPrivilegesByNamesRequest

Note

Prefira as mensagens na tabela anterior quando você precisar saber a profundidade efetiva do privilégio de um usuário. A função RetrieveUserPrivileges (Classe RetrieveUserPrivilegesRequest) retorna apenas a profundidade básica (nível de usuário) para privilégios que o usuário herda por meio de sua associação de equipe, independentemente da profundidade real concedida pelas funções de segurança da equipe.

Exemplo: verificar se um usuário tem um privilégio

Os exemplos a seguir mostram o uso da RetrieveUserPrivilegeByPrivilegeName mensagem. Esta mensagem recupera a lista de privilégios para um usuário do sistema (usuário) de todas as funções diretas associadas ao usuário do sistema e de todas as funções indiretas associadas às equipes das quais o usuário do sistema é membro com base no nome de privilégio especificado.

HasPrivilege O método estático a seguir retorna se o usuário tem o privilégio nomeado.

/// <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;
}

Mais informações:

Recuperar privilégios para uma função de segurança

Você pode recuperar os privilégios associados a uma função de segurança.

O método estático GetRolePrivileges a seguir recupera os privilégios associados a um perfil.

/// <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];
}

Mais informações: Recuperar com linhas relacionadas

Consulte Também

Plug-ins