Сколько копий было сломано относительно RLS на чтение. Пожалуй, это самая главная проблема прав доступа, которую не могли решить программисты 1С.
Все остальное так или иначе делалось кодом, а вот в RLS на чтение приходилось ковыряться в ролях руками. На худой конец — с помощью парсеров, но их никто так и не написал.
Суть проблемы в чем. Допустим, есть RLS по организации и складу.
А затем по некоторым документам нужно добавить RLS по проектам.
При этом нужно было вручную во всех объектах менять RLS-запрос, добавлять отбор по проектам. И шаблоны тут не могли помочь.
Решение я придумал только сейчас, 20 февраля 2026 года. Оно было всегда под носом, как часто бывает.
Оно заключается в том, что для каждого объекта прописываем нужное нам условие в одном шаблоне RLS Общий:

Вот пример такого условия:
#Если "Справочник.Номенклатура" = #ИмяТекущейТаблицы #Тогда ГДЕ Истина #КонецЕсли #Если "Справочник.Контрагенты" = #ИмяТекущейТаблицы #Тогда ГДЕ Ссылка.Наименование ПОДОБНО "а%" #КонецЕсли
Проверяем на контрагентах, без RLS у нас такой список:

С RLS только те контрагенты, что начинаются на букву «а»:

На практике, конечно, будут более осмысленные тексты запросов, например:
#Если "Справочник.Склады" = #ИмяТекущейТаблицы #Тогда ГДЕ Ссылка В (&ДоступныеСклады) #КонецЕсли #Если "Документ.ПоступлениеТоваров" = #ИмяТекущейТаблицы #Тогда ГДЕ Склад В (&ДоступныеСклады) И Организация В (&ДоступныеОрганизации) #КонецЕсли
Сам текст запросов можно по каждому объекту сгенерировать кодом и вставить уже в шаблон.
Наконец-то программисты 1С избавлены от рутины с правами доступа RLS!
Суть моего гениального решения в RLS понятна любому 1с-нику, знакомому с RLS, но попробую объяснить его программистам из других отраслей.
Итак, 1с для каждого объекта (номенклатура, приходная накладная, расходная накладная, …) позволяет наложить ограничение доступа — Record Level Security (RLS).
Но в каждый объект надо заходить и прописывать это ограничение руками. Это может выглядеть так:
Приходная накладная: Организация в &ДоступныеОрганизации и Склад в &ДоступныеСклады
Расходная накладная: Организация в &ДоступныеОрганизации и Склад в &ДоступныеСклады
Организации: Организация в &ДоступныеОрганизации
Склады: Склад в &ДоступныеСклады
Как видите, тут есть повторяющиеся фрагменты, поэтому билиотека БСП в 1С вам предложит использовать шаблоны:
Приходная накладная: ШаблонПрав(«Организация, Склад»)
Расходная накладная: ШаблонПрав(«Организация, Склад»)
Организации: ШаблонПрав(«Организация»)
Склады: ШаблонПрав(«Склад»)
Стало выглядеть короче, да?
Но что, если вы захотите сделать отбор по проекту? Правила с учетом применения шаблонов должны выглядеть так:
Приходная накладная: ШаблонПрав(«Организация, Склад, Проект»)
Расходная накладная: ШаблонПрав(«Организация, Склад, Проект»)
Организации: ШаблонПрав(«Организация»)
Склады: ШаблонПрав(«Склад»)
Проекыт: ШаблонПрав(«Проект»)
Вы обратили внимание, что мы должны зайти в каждый объект и вручную поправить правило. А таких шаблонов может быть много, несколько десятков, а то и сотни.
Поэтому желание вносить изменения в RLS на чтение очень быстро исчезает. К тому же все эти доработки слетят при обновлении 1С. Выход был бы в написании парсера ролей, чтобы выгрузить роли в XML-файлы, поправить, потом загрузить их обратно, но это довольно сложно и никто так и не сподобился его написать.
Суть моего решения в том, чтобы всем объектам прописать общее правило Основной:
Приходная накладная: Основной
Расходная накладная: Основной
Организации: Основной
Склады: Основной
Проекты: Основной
А уже содержание шаблона Основной будет представлять собой один длинный текст, где для каждого вида объектов будет свое правило RLS:
#Если "Справочник.Склады" = #ИмяТекущейТаблицы #Тогда ГДЕ Ссылка В (&ДоступныеСклады) #КонецЕсли #Если "Справочник.Организации" = #ИмяТекущейТаблицы #Тогда ГДЕ Ссылка В (&ДоступныеОрганизации) #КонецЕсли #Если "Документ.ПриходнаяНакладная" = #ИмяТекущейТаблицы #Тогда ГДЕ Склад В (&ДоступныеСклады) И Организация В (&ДоступныеОрганизации) #КонецЕсли #Если "Документ.РасходнаяНакладная" = #ИмяТекущейТаблицы #Тогда ГДЕ Склад В (&ДоступныеСклады) И Организация В (&ДоступныеОрганизации) #КонецЕсли
Тогда если захотеть добавить ограничение по проекту, то поменяется только общий шаблон:
#Если "Справочник.Склады" = #ИмяТекущейТаблицы #Тогда ГДЕ Ссылка В (&ДоступныеСклады) #КонецЕсли #Если "Справочник.Организации" = #ИмяТекущейТаблицы #Тогда ГДЕ Ссылка В (&ДоступныеОрганизации) #КонецЕсли #Если "Справочник.Проекты" = #ИмяТекущейТаблицы #Тогда ГДЕ Ссылка В (&ДоступныеПроекты) #КонецЕсли #Если "Документ.ПриходнаяНакладная" = #ИмяТекущейТаблицы #Тогда ГДЕ Склад В (&ДоступныеСклады) И Организация В (&ДоступныеОрганизации) И Проект В (&ДоступныеПроекты) #КонецЕсли #Если "Документ.РасходнаяНакладная" = #ИмяТекущейТаблицы #Тогда ГДЕ Склад В (&ДоступныеСклады) И Организация В (&ДоступныеОрганизации) И Проект В (&ДоступныеПроекты) #КонецЕсли
И, конечно, этот шаблон лучше и проще генерировать программно.
Основное преимущество в том, что убирается рутинный ручной труд и RLS на чтение пишутся автоматизированно. А ведь раньше это было самой сложной темой именно из-за того, что нужно было прописывать изменения во все роли.
И все это возможно было сделать уже 10 лет назад, при появлении RLS.
Комментарии (20)

itmind
03.03.2026 23:42Влияет ли на производительность шаблон с большим количеством #Если?

fixin Автор
03.03.2026 23:42нет, все компилируется на этапе сохранения метаданных (компиляции), т.е. это не run-time вычисления.
Скорее это аналог макросов в Си, где просто подставляются параметры в результирующий код.
Кстати, так не хватает макросов в Cи Шарп...

Naf2000
03.03.2026 23:42C# содержит директивы препроцессора. Они не настолько развиты как в Си, но с другой стороны, что они там и не нужны

fixin Автор
03.03.2026 23:42я про макросы #Define, это мощная штука.

yesenin_toxa
03.03.2026 23:42В C# есть кодогенерация https://habr.com/en/articles/906778/ и сорсгенерация. Если не достаточно дженериков и экстеншенов, то не слабее штука.

fixin Автор
03.03.2026 23:42ну вот пример.
В зависимости от типа устройства может быть возвращена структура A1, A2 или A3.
Мне надо с результатом вызвать процедуру Work и Bench.
Например:
R = GetValueFromDevice();
If R.code = 1 {
V = R.value as A1;
Work_A1(v);
Bench_A1(v);
}
elseIf R.code = 2 {
V = R.value as A2;
Work_A2(v);
Bench_A2(v);
}
elseIf R.code = 3 {
V = R.value as A3;
Work_A3(v);
Bench_A3(v);
}
Конечно, можно городить обертки над структурами, но это не так красиво, как макросы.

Naf2000
03.03.2026 23:42switch (code) { case 1: Test<A1>(value, Work_A1,Bench_A1); break; case 2: Test<A1>(value, Work_A2, Bench_A2); break; case 3: Test<A3>(value, Work_A3, Bench_A3); break; } static void Test<T>(object a, Action<T> work, Action<T> bench) { T t = (T)a; work(t); bench(t); }

yesenin_toxa
03.03.2026 23:42Если тип устройства, то, конечно, надо смотреть, что за структура -- может надо довести до CLR. Но пусть все просто будет.
-
Путь интерфейсов (он же про дженерики)
// можно и без него, но просто понимать что что-то есть внутри abstract class BaseA { public BaseA(string value) { Value = value; // какое-то создание } public string Value {get; init;} } // можно методы объеденить interface IA { void Work(); void Bench(); } // эти классы по ходу у тебя уже есть // им только добавить интерфейсы class A1: BaseA, IA { public A1(string value): base(value) {} public void Work() { // логика для Work_A1(this.Value) } public void Bench() { // логика для и Bench_A1(this.Value) } } class A2: BaseA, IA { public A2(string value): base(value) {} public void Work() { // логика для Work_A1(this.Value) } public void Bench() { // логика для и Bench_A2(this.Value) } } class A3: BaseA, IA { public A3(string value): base(value) {} public void Work() { // логика для Work_A3(this.Value) } public void Bench() { // логика для и Bench_A3(this.Value) } } // конечный код var R = GetValueFromDevice(); var concrete_A = R.value () switch { 1 => new A1(R.value), 2 => new A2(R.value), 3 => new A3(R.value), _ => throw new Exception("неизвестное устройство") }; concrete_A.Work(); concrete_A.Bench(); // и даже можно будет так var deviceList = new List<IA> { new A1("a1"), new A2("a2"), new A2("a2-2")) }; foreach (var device in deviceList) { device.Work(); device.Bench(); } -
Путь экстеншенов
abstract class BaseA { public BaseA(string value) { Value = value; // какое-то создание } public string Value {get; init;} } class A1: BaseA { public A1(string value): base(value) {} } class A2: BaseA { public A2(string value): base(value) {} } class A3: BaseA { public A3(string value): base(value) {} } // если не интерфейсы, то вот // и для краткости объединяю методы целевые static class AExtensions { static void WorkAndBench(this A1 a) { // Work_A1(a.Value); // Bench_A1(a.Value); } static void WorkAndBench(this A2 a) { // Work_A2(a.Value); // Bench_A2(a.Value); } static void WorkAndBench(this A3 a) { // Work_A3(a.Value); // Bench_A3(a.Value); } } // конечный код var R = GetValueFromDevice(); var concrete_A = R.value () switch { 1 => new A1(R.value), 2 => new A2(R.value), 3 => new A3(R.value), _ => throw new Exception("неизвестное устройство") }; concrete_A.WorkAndBench(); // с колекцией тоже прокатит А так -- патерн chain of responsibility или какой-то другой пайплайн, если девайс один.
Но если вариантов десятки, то генерацию подключать.
-

yesenin_toxa
03.03.2026 23:42А вообще кажется классы не нужны и можно так
var dict = new Dictionary<int, Action<string>> { {1, value => {Work_A1(value); Bench_A1(value);)}, {2, value => {Work_A2(value); Bench_A2(value);)}, {3, value => {Work_A3(value); Bench_A3(value);)} }; R = GetValueFromDevice(); dict[R](R.value);

Naf2000
03.03.2026 23:42В производительном режиме типовых 1С (библиотека БСП) не требуется менять шаблоны RLS. Делается это иначе, например тут описано https://infostart.ru/1c/articles/1656341/
Вам придется этот шаблон скопировать во все роли, использующие RLS. Главное ничего не пропустить. Кроме того, т.к. шаблон хранить ВСЕ правила - это путь к коллизиям файлов при групповой разработке. Во всех ролях.
Ваши примеры не покрывают размещения пользователя в разных областях ограничений. Например, в типовых решениях пользователя можно поместить в группу доступа с ограничением склад "Север", а также в группу доступа с ограничением клиенты менеджера "Вася". В итоге он будет видеть документы по складу "Север" ИЛИ по менеджеру "Вася".

fixin Автор
03.03.2026 23:42при чем тут производительный режим, у которого своя "тележка недостатков"
нет. мне достаточно иметь только одну роль с RLS, если одна роль расово неприемлема и хочется прям разделения по ролям, то во всех ролях, где доступен просмотр, пишите Где ЛОЖЬ, чтобы они не давали право на просмотр.
В статье этого нет, но я приводил вам пример тут https://infostart.ru/1c/articles/2622960/ (в сообщении номер 4), как это решается в "моём случае". Ничего не мешает использовать справочник групп доступа и в моем решении. Методу это не противоречит.

Naf2000
03.03.2026 23:42Какие недостатки типового производительного режима по сравнению с данным решением?
Роль ГДЕ ЛОЖЬ и Роль где отключено право чтения это совершенно разное поведение системы.
Вы меня с кем-то путаете.

fixin Автор
03.03.2026 23:42Производительный режим - https://infostart.ru/1c/articles/1656341/, недостатки:
- нужно рассчитывать по-объектно и хранить эти доступы.
- тяжеловесность решения
- сложность добавления своих отборов, впрочем как и все, что взаимодействует с монструозной БСП.
Помню в Документообороте 2.0 права доступа по-объектно пересчитывались сутками на больших объемах.
Да, это очевидная попытка снизить сложность настройки RLS на чтение, которая была, пока я не предложил этот метод. Этот метод побивает производительный режим.в чем разница? роль с RLS одна, она как раз управляет доступностью объектов на просмотр. Мне достаточно одной роли, это полностью закрывает проблему с видимостью через RLS. Это удобно.
ну если это не вы писали, то почитайте, там пользователь задавал такой же вопрос как вы и я ему подробно ответил.

Naf2000
03.03.2026 23:42В производительном режиме делается иначе, то есть заведомо написали ложь. По поводу "тяжеловесности" и "монструозности" - это все слова, надо подкреплять фактами. Покажите свой продукт, сделайте сравнения
Вы действительно не знаете, чем отсутствие прав отличается от прав, где недоступны все записи? А если на этом принимается системой решение. Если забыть дать право на таблицу - в первом случае у вас выкинет исключение - это плохо конечно, во втором случае ошибок не будет, но будет получен неверный результат, который возможно обнаружат не сразу.
Исходя из написанного - "переобуваемся" на ходу, довешиваем новые данные и... вот уже тоже самое, только свой велосипед, родной )))

fixin Автор
03.03.2026 23:42-- В производительном режиме делается иначе, то есть заведомо написали ложь.
что не так, напишите своими словами.
-- По поводу "тяжеловесности" и "монструозности" - это все слова, надо подкреплять фактами. Покажите свой продукт, сделайте сравнения
несомненно, но перспективы метода уже неплохи. Я давно искал такой. Жаль, раньше не знал, думаю и сейчас кто-то в поисках, им пригодится.
-- Вы действительно не знаете, чем отсутствие прав отличается от прав, где недоступны все записи? А если на этом принимается системой решение. Если забыть дать право на таблицу - в первом случае у вас выкинет исключение - это плохо конечно, во втором случае ошибок не будет, но будет получен неверный результат, который возможно обнаружат не сразу.
приведите пример, не понимаю о чем вы.
-- Исходя из написанного - "переобуваемся" на ходу, довешиваем новые данные и... вот уже тоже самое, только свой велосипед, родной )))
мастер класс обесценивания. но пока что убойных аргументов не увидел, а метод реально хорош.
Junecat
У меня небольшой вопрос к автору: Вы знаете, что фраза «окончательное решение вопроса» несёт в себе некоторый культурный подтекст, и обычно используется только в связи с этим контекстом?
я пишу это потому, что кое кого за такую формулировку уже заминусовали…
fixin Автор
буквоедство - болезнь мозга, которой часто подвержены программисты в силу профессиональной деформации с синтаксис-контролем.
я хоть и программист, но много общался с женщинами, это хорошее противоядие. Рекомендую.
unkas42
Эта "пластинка" про буквоедство - очень удобное оправдание неспособности корректно формулировать мысли.
Значит, корректировка типовых шаблонов у вас слетит при обновлении. А замена типовых шаблонов на ваш Основной не слетит.
fixin Автор
иногда буквоедство это признак граммар-наци.
я предлагаю метод, а как вы будете его использовать - совместно с типовыми ролями или вместо типовых ролей, дело хозяйское.
главное, у программистов по RLS на чтение теперь появился выбор. Раньше его, все 10 лет существования RLS не было. В этом ценность.
Я предлагаю на чтение делать одну роль.
На изменения, конечно, контроль в модулях.
Так будет законченная и логичная система прав в отличии от типовой галочной стыдобы в 1С.