Самостоятельное формирование разрешений и выдача экземпляров ключей

Чтобы построить универсальную систему прав доступа, вы можете самостоятельно формировать разрешения доступа, экземпляры ключей и выдавать экземпляры ключей пользователям. В этом случае можно контролировать права как на уровне элементов проекта, так и на уровне отдельных сущностей (RLS).

Примечание: В приложении этот вариант может совмещаться с простым вариантом, использующим автоматическую выдачу прав (подробнее).

Ключи доступа, добавленные разработчиком

Вы можете добавлять в проект собственные ключи доступа. Для этого предназначены элементы проекта вида КлючДоступа. Элементу проекта этого вида вы можете добавить параметры. Для каждого сочетания значений этих параметров «1С:Шина» будет создавать свой уникальный экземпляр ключа. Подробнее о ключах доступа читайте здесь.

Построение собственной системы прав

В собственной системе прав можно контролировать права как на уровне элементов проекта, так и на уровне отдельных сущностей (RLS). Например, если чтение справочника разрешено, то дальше проверяется право на чтение конкретного элемента справочника. Если оно есть — значит можно читать этот элемент. Если чтение запрещено — значит, этот элемент справочника читать нельзя. Если же чтение всего справочника запрещено, то права на отдельные его элементы не проверяются и чтение любого элемента запрещается.

Для реализации такой системы прав вам потребуется вручную создавать разрешения доступа, экземпляры ключей и устанавливать соответствие пользователей и экземпляров.

Управление доступом в проекте

Каждый вид элементов проекта, для которого поддерживается управление доступом, имеет фиксированный набор прав, предоставляемый платформой. Например, Справочник имеет права Создание, Чтение, Изменение, Удаление.

Каждый элемент проекта этих видов содержит свойство КонтрольДоступа. В этом свойстве вы можете перечислить, каким образом будет контролироваться доступ к тому или иному праву.

Чтобы получить возможность вручную создавать разрешения для того права (тех прав), которые вы хотите контролировать самостоятельно, выберите способ контроля доступа РазрешенияВычисляются или РазрешенияВычисляютсяДляКаждогоОбъекта, например:

КонтрольДоступа: 
    Создание: РазрешеноАутентифицированным
    Чтение: РазрешенияВычисляются
    ПоУмолчанию: РазрешеноАдминистраторам
Эти два способа контроля доступа отличаются следующим:
  • РазрешенияВычисляются позволит вам контролировать права только на уровне всего элемента проекта.
  • РазрешенияВычисляютсяДляКаждогоОбъекта позволит вам контролировать права, и на уровне всего элемента проекта и на уровне отдельных его элементов (RLS).

Вычисление разрешений доступа

Для того чтобы вы могли создать разрешения доступа, у типов встроенного языка, порождаемых элементом проекта, есть события ВычислитьРазрешенияДоступа и ВычислитьРазрешенияДоступаДляОбъектов. Эти события нужно обрабатывать в модулях этих типов, например, в модуле Http-сервиса, в модуле SOAP-сервиса, в модуле регистра сведений.

Предположим, что вы добавили в приложение собственный ключ доступа с именем КлючиГруппСотрудников. Этот ключ имеет один параметр Группа, типа перечисление ГруппыСотрудников. Это перечисление вы тоже добавили сами и оно имеет два элемента: Менеджеры и Руководители. Таким образом вы сможете иметь два экземпляра этого ключа, с помощью которых вы разделите всех пользователей на две группы.

Событие ВычислитьРазрешенияДоступа предназначено для создания разрешений доступа для всего элемента проекта в целом. Оно может выглядеть, например, следующим образом:

@Обработчик
метод ВычислитьРазрешенияДоступа() : Массив<РазрешениеДоступа>

    пер Разрешения: Массив<РазрешениеДоступа>   // массив для возврата разрешений доступа

    // Получить экземпляры ключа доступа
    пер КлючМенеджеров = новый КлючиГруппСотрудников.Объект(ГруппыСотрудников.Менеджеры)
    пер КлючРуководителей = новый КлючиГруппСотрудников.Объект(ГруппыСотрудников.Руководители)

    // Создать разрешение доступа
    Разрешения.Добавить(новый РазрешениеДоступа([КлючМенеджеров, КлючРуководителей], [Сущность.Право.Чтение]))

    возврат Разрешения
;

Здесь чтение справочника в целом разрешается всем пользователям: и тем, кто имеет экземпляр КлючРуководителей, и тем, кто имеет экземпляр КлючМенеджеров.

Событие ВычислитьРазрешенияДоступаДляОбъектов предназначено для создания разрешений доступа для отдельного элемента справочника. Оно может выглядеть, например, следующим образом:

@Обработчик
метод ВычислитьРазрешенияДоступаДляОбъектов(Элементы: ЧитаемыйМассив<Поставщики.Объект>) : ЧитаемоеСоответствие<Поставщики.Объект, Массив<РазрешениеДоступа>>

    пер Результат = <Поставщики.Объект, Массив<РазрешениеДоступа>>{:}   // соответствие для возврата

    // Получить экземпляры ключа доступа
    пер КлючМенеджеров = новый КлючиГруппСотрудников.Объект(ГруппыСотрудников.Менеджеры)
    пер КлючРуководителей = новый КлючиГруппСотрудников.Объект(ГруппыСотрудников.Руководители)
 
    для Элемент из Элементы
        пер Разрешения = <РазрешениеДоступа>[]   // массив для возврата разрешений доступа

        /* Проанализировать свойства элемента справочника, в зависимости от чего 
           либо разрешить менеджерам его чтение, либо нет */
        если Элемент.ВажноеСвойство
            Разрешения.Добавить(новый РазрешениеДоступа([КлючРуководителей], [Сущность.Право.Чтение]))
        иначе
            Разрешения.Добавить(новый РазрешениеДоступа([КлючМенеджеров, КлючРуководителей], [Сущность.Право.Чтение]))
        ;
        Результат.Вставить(Элемент, Разрешения)
    ;
    возврат Результат
;

Здесь, если элемент справочника имеет ВажноеСвойство == Истина, то чтение этого элемента разрешается только тем, кто имеет экземпляр КлючРуководителей. В противном случае элемент справочника могут читать и те, кто имеет экземпляр КлючРуководителей, и те, кто имеет экземпляр КлючМенеджеров.

В каких случаях какие обработчики вам следует иметь? Это зависит от того, какой способ контроля доступа вы выбрали в элементе проекта:
  • если вы выбрали РазрешенияВычисляются, то вы должны иметь только обработчик события ВычислитьРазрешенияДоступа;

  • если вы выбрали РазрешенияВычисляютсяДляКаждогоОбъекта, то вы должны иметь обработчики обоих событий.

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

Но событие ВычислитьРазрешенияДоступа не вызывается автоматически. Для его вызова используйте метод ПересчитатьРазрешенияДоступа() (например, для справочника: имя-справочника.ПересчитатьРазрешенияДоступа()). Такой вызов можно разместить в модуле Проекта.

Событие ВычислитьРазрешенияДоступаДляОбъектов вызывается автоматически при записи элемента справочника. Таким образом, после добавления справочника и записи его элементов в приложении будут нужные разрешения как для самого справочника в целом, так и для его элементов.

Примечание: Событие ВычислитьРазрешенияДоступаДляОбъектов также вызывается в результате вызова метода ПересчитатьРазрешенияДоступаДляОбъектов(). Поскольку этот метод позволяет пересчитать разрешения сразу для нескольких или для всех экземпляров, первый параметр в обработчике ВычислитьРазрешенияДоступаДляОбъектов является массивом экземпляров.

Выдача ключей доступа

К этому же моменту (после добавления справочника и записи его элементов) в системной таблице ключей пользователя тоже будут все необходимые записи. Это происходит потому, что данные в эту таблицу добавляются в момент первого получения экземпляров ключа, которое выполнялось в обработчике события ВычислитьРазрешенияДоступа. Вспомните:

...
    // Получить экземпляры ключа доступа
    пер КлючМенеджеров = новый КлючиГруппСотрудников.Объект(ГруппыСотрудников.Менеджеры)
    пер КлючРуководителей = новый КлючиГруппСотрудников.Объект(ГруппыСотрудников.Руководители)
...

В этот момент у менеджера этого ключа доступа вызывается событие ПроверитьНаличиеКлючейДоступа, в обработчике которого вы и формируете соответствие экземпляра ключа пользователям. Например:

@Обработчик
метод ПроверитьНаличиеКлючейДоступа(Ключи: ЧитаемыйМассив<КлючиГруппСотрудников.Объект>, 
                                    ПользователиДляПроверки: ЧитаемыйМассив<Пользователи.Объект>): 
                                    ЧитаемоеСоответствие<КлючиГруппСотрудников.Объект, ЧитаемыйМассив<Пользователи.Ссылка>>

    знч Результат = <КлючиГруппСотрудников.Объект, Массив<Пользователи.Ссылка>>{:}
    
    для ЭкземплярКлюча из Ключи
        знч ПользователиЭкземпляраКлюча = <Пользователи.Ссылка>[]
        для Пользователь из ПользователиДляПроверки
 
            // Анализировать либо свойства пользователя, либо дополнительную информацию о нем
            // в результате чего относим его либо к менеджерам (ЭтоМенеджер == Истина), либо к руководителям (ЭтоМенеджер == Ложь)
            пер ЭтоМенеджер: Булево

            // Если пользователь – менеджер и экземпляр - КлючМенеджера, то добавить пользователю этот экземпляр
            если ЭтоМенеджер и ЭкземплярКлюча.Группа == ГруппыСотрудников.Менеджеры
                ПользователиЭкземпляраКлюча.Добавить(Пользователь.Ссылка)
            ;
 
            // Если пользователь – руководитель и экземпляр - КлючРуководителя, то добавить пользователю этот экземпляр
            если не ЭтоМенеджер и ЭкземплярКлюча.Группа == ГруппыСотрудников.Руководители
                ПользователиЭкземпляраКлюча.Добавить(Пользователь.Ссылка)
            ;
        ;
        Результат.Вставить(ЭкземплярКлюча, ПользователиЭкземпляраКлюча)
    ;
    возврат Результат
;
Экземпляр ключа передается в этот обработчик как элемент массива потому, что событие ПроверитьНаличиеКлючейДоступа платформа вызывает в следующих случаях:
  • При получении экземпляра ключа доступа по набору параметров во встроенном языке: новый имя-ключа-доступа.Объект() — в этом случае в обработчик передается экземпляр ключа и все подключенные пользователи;
  • При подключении нового пользователя к приложению — в этом случае обработчик вызывается у каждого ключа доступа, которые есть в проекте, и в него передаются все экземпляры этих ключей и подключившийся пользователь.