← Назад к справке

CRM

Права доступа CRM

Рабочая справка по проверке прав CRM в коробочном Bitrix24 через PHP: UserPermissions, CCrmAuthorizationHelper, CCrmPerms и операции CRM.

Если код работает от администратора или из агента, легко случайно обойти пользовательские ограничения. Поэтому для пользовательских сценариев лучше явно проверять права или запускать операцию в контексте нужного пользователя.

Общее понимание

Права CRM зависят от роли, отдела, ответственного, воронки и конкретной сущности.

Как устроены права CRM

В интерфейсе CRM права задаются ролями. В коде можно проверять доступ к конкретной карточке, к типу сущности или к воронке.

Что проверить Пример
Доступ к конкретной сделке Может ли пользователь прочитать сделку с ID 123.
Доступ к типу Может ли пользователь читать хоть какие-то сделки.
Доступ к воронке Может ли пользователь читать сделки в воронке 5.
Доступ при операции Можно ли изменить карточку через операцию CRM.

Права текущего и другого пользователя

Сервис прав можно получить для текущего пользователя или для конкретного пользователя по ID.

<?php

use Bitrix\Main\Loader;
use Bitrix\Crm\Service;

Loader::includeModule('crm');

/**
 * Получает сервис прав текущего пользователя.
 */
function fetchCurrentUserPermissions()
{
    return Service\Container::getInstance()->getUserPermissions();
}

/**
 * Получает сервис прав конкретного пользователя.
 */
function fetchUserPermissions(int $user_id)
{
    return Service\Container::getInstance()->getUserPermissions($user_id);
}

$current_permissions = fetchCurrentUserPermissions();
$user_permissions = fetchUserPermissions($user_id);

Проверки через новое API

В новом API проверки прав доступны через сервис UserPermissions.

Проверить чтение элемента

<?php

use Bitrix\Main\Loader;
use Bitrix\Crm\Service;

const CRM_DEAL_TYPE_ID = \CCrmOwnerType::Deal;

Loader::includeModule('crm');

/**
 * Проверяет право чтения CRM-элемента.
 */
function canUserReadCrmItem(int $user_id, int $entity_type_id, int $entity_id): bool
{
    $user_permissions = Service\Container::getInstance()->getUserPermissions($user_id);

    return $user_permissions->item()->canRead($entity_type_id, $entity_id);
}

$can_read = canUserReadCrmItem($user_id, CRM_DEAL_TYPE_ID, $deal_id);

var_dump($can_read);

Проверить изменение и удаление

<?php

use Bitrix\Main\Loader;
use Bitrix\Crm\Service;

const CRM_DEAL_TYPE_ID = \CCrmOwnerType::Deal;

Loader::includeModule('crm');

/**
 * Проверяет права на изменение и удаление CRM-элемента.
 */
function checkCrmItemWritePermissions(int $user_id, int $entity_type_id, int $entity_id): array
{
    $user_permissions = Service\Container::getInstance()->getUserPermissions($user_id);

    return [
        'can_update' => $user_permissions->item()->canUpdate($entity_type_id, $entity_id),
        'can_delete' => $user_permissions->item()->canDelete($entity_type_id, $entity_id),
    ];
}

$permissions = checkCrmItemWritePermissions($user_id, CRM_DEAL_TYPE_ID, $deal_id);

print_r($permissions);

Проверить доступ к типу сущности

Иногда нужно проверить не конкретную карточку, а доступ пользователя к типу CRM в целом или к воронке.

<?php

use Bitrix\Main\Loader;
use Bitrix\Crm\Service;

const CRM_DEAL_TYPE_ID = \CCrmOwnerType::Deal;

Loader::includeModule('crm');

/**
 * Проверяет доступ к сделкам в целом и в конкретной воронке.
 */
function checkDealTypePermissions(int $user_id, int $category_id): array
{
    $user_permissions = Service\Container::getInstance()->getUserPermissions($user_id);

    return [
        'can_read_deals' => $user_permissions->entityType()->canReadItems(CRM_DEAL_TYPE_ID),
        'can_read_category_deals' => $user_permissions->entityType()->canReadItemsInCategory(
            CRM_DEAL_TYPE_ID,
            $category_id
        ),
    ];
}

$permissions = checkDealTypePermissions($user_id, $category_id);

print_r($permissions);

Старые проверки

В старом CRM-коде часто встречаются CCrmPerms и CCrmAuthorizationHelper.

CCrmAuthorizationHelper

Этот вариант часто встречается в старом коде коробки. Для новых статей и нового кода лучше смотреть в сторону сервиса UserPermissions, но старый подход полезно уметь читать.

<?php

use Bitrix\Main\Loader;

Loader::includeModule('crm');

/**
 * Проверяет право чтения сделки старым способом.
 */
function canReadDealOldWay(int $deal_id): bool
{
    $user_permissions = \CCrmPerms::GetCurrentUserPermissions();

    return \CCrmAuthorizationHelper::CheckReadPermission(
        \CCrmOwnerType::Deal,
        $deal_id,
        $user_permissions
    );
}

$can_read = canReadDealOldWay($deal_id);

var_dump($can_read);

CCrmPerms

CCrmPerms — старый объект прав CRM. Его часто передают в старые методы проверки, чтобы не получать права заново в каждом вызове.

<?php

/**
 * Получает старый объект прав CRM текущего пользователя.
 */
function fetchCurrentCrmPerms(): \CCrmPerms
{
    return \CCrmPerms::GetCurrentUserPermissions();
}

$user_permissions = fetchCurrentCrmPerms();

Операции CRM

Операции фабрики могут сами проверять права, если проверка не отключена.

Проверка прав в операции

По умолчанию операция может проверять доступ. Если в служебном скрипте проверку отключают, это нужно делать осознанно.

$operation = $factory->getUpdateOperation($item);

$operation->enableCheckAccess();

$operation_result = $operation->launch();

if (!$operation_result->isSuccess()) {
    print_r($operation_result->getErrorMessages());
}
$operation = $factory->getUpdateOperation($item);

// Только для служебных сценариев, где права проверены отдельно.
$operation->disableCheckAccess();

$operation_result = $operation->launch();

Контекст пользователя

Операцию можно запустить в контексте конкретного пользователя. Тогда проверки и связанные действия будут учитывать этого пользователя.

<?php

use Bitrix\Main\Loader;
use Bitrix\Crm\Service;

const CRM_DEAL_TYPE_ID = \CCrmOwnerType::Deal;

Loader::includeModule('crm');

/**
 * Изменяет сделку в контексте пользователя.
 */
function updateDealTitleWithUserContext(int $deal_id, string $title, int $user_id): array
{
    $factory = Service\Container::getInstance()->getFactory(CRM_DEAL_TYPE_ID);

    if ($factory === null) {
        return [
            'is_success' => false,
            'error_messages' => ['Фабрика сделок не найдена'],
        ];
    }

    $deal_item = $factory->getItem($deal_id);

    if ($deal_item === null) {
        return [
            'is_success' => false,
            'error_messages' => ['Сделка не найдена'],
        ];
    }

    $deal_item->setTitle($title);

    $context = new Service\Context();
    $context->setUserId($user_id);

    $operation = $factory->getUpdateOperation($deal_item, $context);
    $operation->enableCheckAccess();

    $operation_result = $operation->launch();

    return [
        'is_success' => $operation_result->isSuccess(),
        'error_messages' => $operation_result->getErrorMessages(),
    ];
}

$result = updateDealTitleWithUserContext($deal_id, $title, $user_id);

print_r($result);

Источники