UserPermissions
Права доступа
Права доступа - всегда довольно сложный раздел бизнес-логики любого приложения.
При проектировании публичного API этого сервиса фокус был сделан на ответах на простые вопросы.
Сам этот сервис практически не работает напрямую с хранением настроек и атрибутов прав доступа, это только фасад с удобным API.
Тем не менее, ниже немного описывается структура таблиц и особенности проверки прав доступа.
Настройки прав доступа
Права доступа в CRM (как во многих других модулях) настраиваются на уровне ролей (таблица b_crm_role
).
К каждой роли можно отнести пользователя / группу / подразделение и т.д. (таблица b_crm_role_relation
).
На каждую роль настраиваются права доступа (таблица b_crm_role_perms
).
Права доступа настраиваются в разрезе "сущности" (колонка ENTITY, это горизонтальная строка в интерфейсе настроек).
Для каждой сущности можно настроить определенный уровень прав (колонка ATTR) для определенного действия (колонка PERM_TYPE).
Хранение атрибутов
Каждый раз при создании / изменении элемента любого типа CRM, его данные, влияющие на права доступа, преобразуются в набор атрибутов и записывается в таблицу b_crm_entity_perms
(метод \CCrmPerms::UpdateEntityAttr
).
Соответствие между этими данными и получаемыми атрибутами представлено в таблице:
Данные элемента | Пример значения атрибута | |
---|---|---|
Поле Ответственный | U1 | 1 - идентификатор пользователя |
Поле Ответственный | IU1 | 1 - идентификатор пользователя как сотрудника |
Принадлежность ответственного к подразделениям орг. структуры | D2 | 2 - идентификатор подразделения. Сохраняется как принадлежность к подразделению, так и принадлежность ко всем родительским подразделениям |
Поле "Доступна (доступен) для всех" | O | Если галка в поле установлена, то атрибут есть, а если нет то нет |
Является ли компания "моей компанией" (Для компаний) | IS_MY_COMPANY | Если компания является моей компанией, то атрибут есть и к таким записям доступ на чтение есть всегда, независимо от настроек доступа для остальных компаний |
Список наблюдателей (Для лидов и сделок) | CU1 | 1 - идентификатор пользователя. Для каждого наблюдателя добавляется свой атрибут в список |
Значение статуса/стадии (Для лидов) | STATUS_IDNEW | NEW - идентификатор статуса |
Значение стадии (Для сделок и коммерческих предложений)) | STAGE_IDNEW | NEW - идентификатор стадии |
Далее при проверке прав доступа алгоритм следующий:
- для пользователя, относительно которого проверяются права доступа, получается список его ролей, из ролей и их разрешений строится карта атрибутов, доступных этому пользователю (метод
\CCrmRole::GetUserPerms()
); - карта разрешений сравнивается с текущим набором атрибутов элемента с учетом действия, которое производится (
\CCrmPerms::CheckEnityAccess()
); - для списочных запросов строится дополнительное выражение для добавления в WHERE (метод
\CCrmPerms::BuildSql()
).
В этом сервисе все эти действия спрятаны "под капотом" (по факту вызываются методы старого API).
Инстанс сервиса следует получать из контейнера, т.к. внутри сервиса данные закешированы.
В методе Service\Container::getUserPermissions()
есть аргумент $userId, куда можно передать идентификатор пользователя.
Методы
Метод | Описание | С версии |
---|---|---|
public function __construct(int $userId)
|
Конструктор.
Если $userId = 0, то считается, что действие производится от системного пользователя. Этот пользователь не имеет ни на что доступа. Если надо произвести действия без учета прав доступа, то их проверку необходимо отключить в операции. | |
public function getUserId(): int |
Вернет идентификатор пользователя. | |
public function getCrmPermissions(): \CCrmPerms |
Вернет объект класса \CCrmPerms , завязанного на текущего пользователя. | |
public function canWriteConfig(): bool |
Вернет true, если пользователь имеет право изменять настройки CRM. | |
public function canReadConfig(): bool |
Вернет true, если пользователь имеет право читать настройки CRM. | |
public function canReadType(int $entityTypeId, int $categoryId = 0): bool
|
Вернет true, если пользователь имеет право просматривать элементы типа $entityTypeId хотя бы в одном из направлений типа. | |
public function canReadTypeInCategory(int $entityTypeId, int $categoryId): bool
|
Вернет true, если пользователь имеет право имеет право просматривать элементы типа $entityTypeId в направлении $categoryId. | crm 22.0.0 |
public function canAddType(): bool |
Вернет true, если пользователь имеет право создать новый смарт-процесс. | |
public function canUpdateType(): bool |
Вернет true, если пользователь имеет право изменить настройки смарт-процесса с идентификатором типа CRM $entityTypeId. | |
public function canAddItem(Item $item): bool |
Вернет true, если пользователь имеет право создать элемент $item в его текущем состоянии. | |
public function checkAddPermissions (int $entityTypeId, int $categoryId = 0, ?string $stageId = null): bool |
Вернет true, если пользователь имеет право создать элемент типа $entityTypeId в направлении $categoryId на стадии $stageId.
Здесь и ниже, если направление не указано, то проверка будет произведена для направления по умолчанию. Если стадия не указана, то проверка прав с учетом стадии производиться не будет. | |
public function checkUpdatePermissions (int $entityTypeId, int $id, int $categoryId = 0): bool |
Вернет true, если пользователь имеет право изменить элемент с идентификатором $id в направлении $categoryId. | |
public function canUpdateItem(Item $item): bool |
Вернет true, если пользователь имеет право изменить элемент $item. | |
public function checkDeletePermissions (int $entityTypeId, int $id, int $categoryId = 0): bool |
Вернет true, если пользователь имеет право удалить элемент типа $entityTypeId с идентификатором $id в направлении $categoryId. | |
public function canDeleteItem(Item $item): bool |
Вернет true, если пользователь имеет право удалить элемент $item. | |
public function checkReadPermissions (int $entityTypeId, int $id = 0, int $categoryId = 0): bool |
Вернет true, если пользователь может прочитать элемент типа $entityTypeId с идентификатором $id в направлении $categoryId. | |
public function canReadItem(Item $item): bool |
Вернет true, если пользователь имеет право прочитать элемент $item. | |
public function canViewItemsInCategory (Category $category): bool |
Вернет true, если пользователь имеет право прочитать элементы $item направления $category. | |
public function canAddCategory (Category $category): bool |
Вернет true, если пользователь имеет право создать новое направление $category. | |
public function canUpdateCategory (Category $category): bool |
Вернет true, если пользователь имеет право изменить направление $category. | |
public function canDeleteCategory (Category $category): bool |
Вернет true, если пользователь имеет право удалить направление $category. | |
public function filterAvailableForReadingCategories (array $categories): array |
Вернет массив направлений из набора $categories, в которых пользователь может просматривать элементы. | |
public function getPermissionType (Item $item, string $operationType = self::OPERATION_READ): string |
Вернет строковый идентификатор уровня доступа (все / свои и своего отдела / свои / только открытые / нет), который есть у пользователя к элементу $item при выполнении операции $operationType. | |
public function prepareItemPermissionAttributes (Item $item): array |
Вернет набор атрибутов элемента $item перед его сохранением в таблицу b_crm_entity_perms. | |
public static function getItemPermissionEntityType (Item $item): string |
Вернет строковый идентификатор сущности для таблицы прав элемента $item. | |
public static function getPermissionEntityType (int $entityTypeId, int $categoryId = 0): string |
Вернет строковый идентификатор сущности для таблицы прав типа сущности $entityTypeId в направлении $categoryId. | |
public static function getEntityNameByPermissionEntityType (string $permissionEntityType): ?string |
Вернет строковый идентификатор типа сущности CRM по строковому идентификатору сущности $permissionEntityType для таблицы прав. | |
public function applyAvailableItemsFilter (?array $filter, array $permissionEntityTypes, ?string $operation = self::OPERATION_READ, ?string $primary = 'ID'): array
|
Дополнит $filter дополнительными ключами, которые позволят отобрать только те элементы, к которым пользователь имеет доступ. Вернет новую версию фильтра. | |
public function getStartStageId(int $entityTypeId, EO_Status_Collection $stages, int $categoryId = 0, string $operation = self::OPERATION_ADD): ?string
|
Вернет идентификатор первой стадии из коллекции $stages типа $entityTypeId направления $categoryId, к которой имеет доступ пользователь при выполнении операции типа $operation.
Обычно этот метод используется, чтоб определить, в какую стадию надо поместить создаваемый пользователем элемент. |
Примеры
use Bitrix\Crm\Service; $entityTypeId = 150; $factory = Service\Container::getInstance()->getFactory($entityTypeId); if (!$factory) { return; } $userPermissions = Service\Container::getInstance()->getUserPermissions(); $canWriteConfig = $userPermissions->canWriteConfig(); $category = $factory->getDefaultCategory (); $canReadType = $userPermissions->canReadType ( $factory->getEntityTypeId (), $category->getId() ); $canUpdateCategory = $userPermissions->canUpdateCategory($category); $item = $factory->getItem(12); $canDeleteItem = $userPermissions->canDeleteItem($item); $canAddItemToCategory = $userPermissions->checkAddPermissions( $factory->getEntityTypeId (), $category->getId() ); $categories = $factory->getCategories(); $availableForReadItemsCategories = $userPermissions->filterAvailableForReadingCategories($categories); $filter = [ '=CATEGORY_ID' => $category->getId(), '>ID' => 100, ]; $permissionEntityTypes = [$userPermissions::getPermissionEntityType($factory->getEntityTypeId, $category->getId())]; $filterWithPermissions = $userPermissions->applyAvailableItemsFilter($filter, $permissionEntityTypes);