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);
Пользовательские комментарии
Мы будем рады, если разработчики добавят свои комментарии по практическому использованию методов системы.Для этого нужно всего лишь авторизоваться на сайте
Но помните, что Пользовательские комментарии, несмотря на модерацию, не являются официальной документацией. Ответственность за их использование несет сам пользователь.
Также Пользовательские комментарии не являются местом для обсуждения функционала. По подобным вопросам обращайтесь на форумы.