Ошибка 1С «Нарушение прав доступа!» значит, что у пользователя нет права на объект или действие, которое выполняет программа: прочитать регистр, открыть обработку, провести документ. Какого права и на какой объект не хватило, окно не говорит, и соблазн один — выдать «Полные права». Ниже — как найти таблицу и право по журналу регистрации и в отладчике, отличить нехватку роли от ограничения на уровне записей (RLS) и выдать ровно ту роль, которой не хватает.
Сообщений о правах несколько, и уже по тексту видно, где искать причину:
| Текст ошибки | Что произошло | Что проверять |
|---|---|---|
| «Нарушение прав доступа!» | В ролях нет права на объект или действие: чтение таблицы, использование обработки, открытие внешней обработки | Какая роль даёт право и в каком она профиле |
| «У пользователя недостаточно прав на исполнение операции над базой данных» | Право есть, но его сужает ограничение на уровне записей: запрос без РАЗРЕШЕННЫЕ, чтение или запись запрещённой строки | Запрос и значения доступа в группах |
| «Недостаточно прав для просмотра», «…для редактирования», «…для проведения» | Действие в форме без интерактивного права: «Просмотр», «Редактирование», «Интерактивное проведение» | Профиль сотрудника |
| «Недостаточно прав для изменения данных: …» | Запись не прошла проверку ограничений БСП (сверено по УТ 11.4 и КА 2.5) | Значения доступа в группах |
| «Нет прав на запуск требуемого вида клиента» | Нет права запуска тонкого или веб-клиента | Роль «Запуск тонкого клиента» в профиле |
Главное различие — в первых двух строках. «Нарушение прав доступа!» лечится ролью. Ошибку «у пользователя недостаточно прав на исполнение операции» роль не исправит: право уже есть, и запрещённые строки нужно либо не читать (РАЗРЕШЕННЫЕ в запросе), либо открыть через значения доступа. «Полные права» убирают обе ошибки и все ограничения сразу: права ролей складываются, и роль без условия перекрывает условия остальных.
Типичные ситуации: после обновления или доработки появился объект, которого нет ни в одной роли; отчёт работает у администратора и падает у менеджера; не открывается внешняя обработка; регламентное задание идёт под техническим пользователем с урезанным профилем.
Отказ платформа пишет в журнал регистрации событием «Доступ. Отказ в доступе»: в колонке «Метаданные» — объект, в «Данных» — недостающее право, а для ограничения на уровне записей — действие (чтение, изменение и т. п.). Отберите журнал по пользователю и этому событию (где журнал в вашей конфигурации — в статье про журнал регистрации) или выгрузите отказы кодом под администратором:
// Отказы в доступе из журнала регистрации: когда, кто, к какому объекту
// и какого права не хватило. Серверный код: модуль объекта обработки
// или общий модуль «Сервер». Нужно право «Журнал регистрации».
Функция ОтказыВДоступе(Знач ЧасовНазад = 24, Знач ИмяПользователя = "") Экспорт
Отбор = Новый Структура;
Отбор.Вставить("ДатаНачала", ТекущаяДатаСеанса() - ЧасовНазад * 3600);
Отбор.Вставить("Событие", "_$Access$_.AccessDenied");
Если ЗначениеЗаполнено(ИмяПользователя) Тогда
Отбор.Вставить("Пользователь", ИмяПользователя);
КонецЕсли;
События = Новый ТаблицаЗначений;
// Только последние 500 записей: при массовой ошибке их бывают тысячи.
ВыгрузитьЖурналРегистрации(События, Отбор,
"Дата,ИмяПользователя,Метаданные,Данные,ПредставлениеДанных,Комментарий", , 500);
Строки = Новый Массив;
Для Каждого Событие Из События Цикл
Строки.Добавить(СтрШаблон("%1 | %2 | %3 | %4",
Формат(Событие.Дата, "ДФ='dd.MM.yyyy HH:mm:ss'"),
Событие.ИмяПользователя,
ИменаОбъектовСобытия(Событие.Метаданные),
ЧегоНеХватило(Событие)));
КонецЦикла;
Если Строки.Количество() = 0 Тогда
Возврат "Отказов в доступе за период нет.";
КонецЕсли;
Возврат СтрСоединить(Строки, Символы.ПС);
КонецФункции
// У событий доступа в колонке Метаданные бывает строка или массив имён.
Функция ИменаОбъектовСобытия(ИменаМетаданных)
Если ТипЗнч(ИменаМетаданных) = Тип("Массив") Тогда
Возврат СтрСоединить(ИменаМетаданных, ", ");
КонецЕсли;
Возврат Строка(ИменаМетаданных);
КонецФункции
// Не хватило права роли — в Данных структура с ключом «Право».
// Сработало ограничение на уровне записей — с ключом «Действие».
Функция ЧегоНеХватило(Событие)
Данные = Событие.Данные;
Если ТипЗнч(Данные) = Тип("Структура") Тогда
Если Данные.Свойство("Право") Тогда
Возврат "нет права: " + Данные.Право;
ИначеЕсли Данные.Свойство("Действие") Тогда
Возврат "ограничение на уровне записей, действие: " + Данные.Действие;
КонецЕсли;
КонецЕсли;
Возврат СокрЛП(Событие.ПредставлениеДанных + " " + Событие.Комментарий);
КонецФункции
"_$Access$_.AccessDenied" — системное имя события, в отборе его задают так. Пользователя можно передать строкой: так находятся и записи удалённых пользователей.Журнал показывает, чего не хватило, отладчик — на какой строке. Первая строка подробного текста ошибки в фигурных скобках уже содержит модуль и номер строки. Если ошибка внутри Попытка или глубоко в общем модуле:
// Выражения для табло отладчика: остановитесь на строке с ошибкой
// в серверном контексте и подставьте свою таблицу.
ПользователиИнформационнойБазы.ТекущийПользователь().Имя
ПравоДоступа("Чтение", Метаданные.РегистрыНакопления.ТоварыНаСкладах)
ПараметрыДоступа("Чтение", Метаданные.РегистрыНакопления.ТоварыНаСкладах, "Номенклатура").ОграничениеУсловием
ПривилегированныйРежим()
БезопасныйРежим()
ПравоДоступа = Ложь — не хватает роли. Истина вместе с ОграничениеУсловием = Истина и запросом без РАЗРЕШЕННЫЕ — это RLS. ПривилегированныйРежим() и БезопасныйРежим() пригодятся для обработок, о них ниже. Запрос к нескольким таблицам удобнее проверить целиком: функция разбирает текст схемой запроса и проверяет права текущего пользователя на каждую таблицу.
// Проверка запроса до выполнения: на какие таблицы у текущего пользователя
// нет права «Чтение» и где без РАЗРЕШЕННЫЕ сработает ограничение на уровне записей.
// Серверный код: модуль объекта обработки или общий модуль «Сервер».
Функция ПроблемыПравВЗапросе(Знач ТекстЗапроса) Экспорт
Схема = Новый СхемаЗапроса;
Схема.УстановитьТекстЗапроса(ТекстЗапроса);
Проблемы = Новый Массив;
Для Каждого ЗапросПакета Из Схема.ПакетЗапросов Цикл
// Запросы УНИЧТОЖИТЬ данных не читают.
Если ТипЗнч(ЗапросПакета) = Тип("ЗапросВыбораСхемыЗапроса") Тогда
ПроверитьЗапросСхемы(ЗапросПакета, ЗапросПакета.ВыбиратьРазрешенные, Проблемы);
КонецЕсли;
КонецЦикла;
Возврат Проблемы;
КонецФункции
Процедура ПроверитьЗапросСхемы(ЗапросСхемы, Разрешенные, Проблемы)
Для Каждого Оператор Из ЗапросСхемы.Операторы Цикл
Для Каждого ИсточникСхемы Из Оператор.Источники Цикл
Источник = ИсточникСхемы.Источник;
Если ТипЗнч(Источник) = Тип("ВложенныйЗапросСхемыЗапроса") Тогда
// РАЗРЕШЕННЫЕ внешнего запроса действует и на вложенный.
ПроверитьЗапросСхемы(Источник.Запрос, Разрешенные, Проблемы);
Продолжить;
ИначеЕсли ТипЗнч(Источник) <> Тип("ТаблицаСхемыЗапроса") Тогда
Продолжить; // таблица из менеджера временных таблиц
КонецЕсли;
// "РегистрНакопления.ТоварыНаСкладах.Остатки" -> "РегистрНакопления.ТоварыНаСкладах"
Части = СтрРазделить(Источник.ИмяТаблицы, ".");
Если Части.Количество() < 2 Тогда
Продолжить; // временная таблица этого же пакета
КонецЕсли;
ПолноеИмя = Части[0] + "." + Части[1];
ОбъектМД = Метаданные.НайтиПоПолномуИмени(ПолноеИмя);
// Перечисления прав не имеют, внешние источники здесь не разбираем.
Если ОбъектМД = Неопределено Или Части[0] = "ВнешнийИсточникДанных"
Или Метаданные.Перечисления.Содержит(ОбъектМД) Тогда
Продолжить;
КонецЕсли;
Если Не ПравоДоступа("Чтение", ОбъектМД) Тогда
Текст = ПолноеИмя + ": нет права «Чтение» — будет «Нарушение прав доступа!»";
ИначеЕсли Не Разрешенные И ЕстьОграничениеЧтения(ОбъектМД) Тогда
Текст = ПолноеИмя + ": чтение ограничено на уровне записей, а в запросе нет РАЗРЕШЕННЫЕ";
Иначе
Продолжить;
КонецЕсли;
Если Проблемы.Найти(Текст) = Неопределено Тогда
Проблемы.Добавить(Текст);
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
// Истина, если чтение таблицы для текущего пользователя ограничено условием (RLS).
Функция ЕстьОграничениеЧтения(ОбъектМД)
Попытка
Возврат ПараметрыДоступа("Чтение", ОбъектМД, ПолеДляПараметровДоступа(ОбъектМД)).ОграничениеУсловием;
Исключение
// У констант ограничений на уровне записей нет.
Возврат Ложь;
КонецПопытки;
КонецФункции
// ПараметрыДоступа ждёт список полей: у ссылочных таблиц берём Ссылка,
// у регистров — первое измерение (или ресурс, если измерений нет).
Функция ПолеДляПараметровДоступа(ОбъектМД)
ЭтоРегистр = Метаданные.РегистрыСведений.Содержит(ОбъектМД)
Или Метаданные.РегистрыНакопления.Содержит(ОбъектМД)
Или Метаданные.РегистрыБухгалтерии.Содержит(ОбъектМД)
Или Метаданные.РегистрыРасчета.Содержит(ОбъектМД);
Если Не ЭтоРегистр Тогда
Возврат "Ссылка";
КонецЕсли;
Если ОбъектМД.Измерения.Количество() > 0 Тогда
Возврат ОбъектМД.Измерения[0].Имя;
КонецЕсли;
Возврат ОбъектМД.Ресурсы[0].Имя;
КонецФункции
СхемаЗапроса (8.3.5 и новее) раскладывает пакет на запросы и источники; вложенные запросы получают признак РАЗРЕШЕННЫЕ внешнего.РегистрНакопления.ТоварыНаСкладах.Остатки берём две первые части: права на виртуальную таблицу — это права на регистр.С внешними обработками ошибка встречается чаще всего. Причин три:
УстановитьПривилегированныйРежим(Истина) игнорируется. Так работают обработки, подключённые через ВнешниеОбработки.Подключить без третьего параметра, и дополнительные обработки БСП, если разработчик не снял БезопасныйРежим в сведениях о регистрации (по умолчанию там Истина). Режим подключения БСП пишет в журнал примечанием «Подключение, БезопасныйРежим = …» (сверено по УТ 11.4).Чтобы 1С-обработка не выдавала голое нарушение прав доступа, пусть проверяет права до запроса. Пример для модуля объекта, использует функцию из листинга выше:
// Модуль объекта внешней обработки: прежде чем выполнять запрос, проверяем права
// и показываем понятный текст вместо «Нарушение прав доступа!».
// ПроблемыПравВЗапросе — функция из листинга выше, в этом же модуле.
Функция ОстаткиТоваров() Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| Остатки.Номенклатура КАК Номенклатура,
| Остатки.Склад КАК Склад,
| Остатки.ВНаличииОстаток КАК ВНаличии
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки";
Проблемы = ПроблемыПравВЗапросе(Запрос.Текст);
Если Проблемы.Количество() > 0 Тогда
ВызватьИсключение "Обработке не хватает прав. Передайте этот текст администратору:"
+ Символы.ПС + СтрСоединить(Проблемы, Символы.ПС);
КонецЕсли;
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Стандартная альтернатива — ВыполнитьПроверкуПравДоступа("Чтение", Метаданные.РегистрыНакопления.ТоварыНаСкладах) в начале серверной процедуры: исключение плюс запись «Доступ. Отказ в доступе» в журнале. Подключение обработок к типовой — в статье про дополнительные обработки.
Роль решает, может ли пользователь работать с таблицей вообще, ограничение на уровне записей — с какими строками:
РАЗРЕШЕННЫЕ не поможет. Нужна роль или код конфигурации в привилегированном режиме.ВЫБРАТЬ РАЗРЕШЕННЫЕ, а если сотрудник должен видеть эти строки, добавьте ему значения доступа: организацию, склад, группу партнёров. Как устроены ограничения БСП — в статье про RLS в 1С.УправлениеДоступом.ЧтениеРазрешено(Ссылка, Пользователь) (сверено по УТ 11.4 и КА 2.5; для другого пользователя нужны административные права).Объект и право известны — ищем роли, которые его дают, и проверяем, есть ли они у сотрудника. Код под администратором, ПолеДляПараметровДоступа — из листинга с проверкой запроса.
// Какие роли дают право на объект и есть ли они у пользователя.
// Под администратором: ПравоДоступа с ролью или пользователем в третьем
// параметре требует административных прав. Пример вызова:
// ИменаРолей = Неопределено;
// Сообщить(РолиСПравом("РегистрНакопления.ТоварыНаСкладах", "Чтение", "Кладовщик", ИменаРолей));
Функция РолиСПравом(Знач ПолноеИмяОбъекта, Знач Право, Знач ИмяПользователя = "", ИменаРолей = Неопределено) Экспорт
ОбъектМД = Метаданные.НайтиПоПолномуИмени(ПолноеИмяОбъекта);
Если ОбъектМД = Неопределено Тогда
ВызватьИсключение "Не найден объект метаданных " + ПолноеИмяОбъекта;
КонецЕсли;
ПользовательИБ = Неопределено;
Если ЗначениеЗаполнено(ИмяПользователя) Тогда
ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоИмени(ИмяПользователя);
Если ПользовательИБ = Неопределено Тогда
ВызватьИсключение "Не найден пользователь информационной базы " + ИмяПользователя;
КонецЕсли;
КонецЕсли;
ИменаРолей = Новый Массив;
Строки = Новый Массив;
Для Каждого Роль Из Метаданные.Роли Цикл
// Административные роли БСП дают всё — их не предлагаем.
Если Роль.Имя = "ПолныеПрава" Или Роль.Имя = "АдминистраторСистемы"
Или Не ПравоДоступа(Право, ОбъектМД, Роль) Тогда
Продолжить;
КонецЕсли;
ИменаРолей.Добавить(Роль.Имя);
Пункт = Роль.Имя;
Попытка
// Истина — роль даёт право с ограничением на уровне записей (RLS).
Если ПараметрыДоступа(Право, ОбъектМД, ПолеДляПараметровДоступа(ОбъектМД), Роль).ОграничениеУсловием Тогда
Пункт = Пункт + " (с ограничением на уровне записей)";
КонецЕсли;
Исключение
// У обработок, отчётов и констант ограничений на уровне записей нет.
КонецПопытки;
Если ПользовательИБ <> Неопределено И ПользовательИБ.Роли.Содержит(Роль) Тогда
Пункт = Пункт + " — есть у пользователя";
КонецЕсли;
Строки.Добавить(Пункт);
КонецЦикла;
Если ИменаРолей.Количество() = 0 Тогда
Строки.Добавить("Право «" + Право + "» на " + ПолноеИмяОбъекта
+ " дают только административные роли.");
КонецЕсли;
Если ПользовательИБ <> Неопределено Тогда
Строки.Добавить(?(ПравоДоступа(Право, ОбъектМД, ПользовательИБ),
"Итог: у пользователя право есть.",
"Итог: права нет, нужна одна из ролей выше."));
КонецЕсли;
Возврат СтрСоединить(Строки, Символы.ПС);
КонецФункции
В БСП роли назначают через профили групп доступа. Вторая функция показывает, в каких профилях и группах найденные роли уже есть:
// БСП (сверено по УТ 11.4 и КА 2.5): в каких профилях и группах доступа
// есть роли из списка. ИменаРолей — массив, который заполнила РолиСПравом.
Функция ПрофилиИГруппыСРолями(Знач ИменаРолей) Экспорт
ПолныеИмена = Новый Массив;
Для Каждого ИмяРоли Из ИменаРолей Цикл
ПолныеИмена.Добавить("Роль." + ИмяРоли);
КонецЦикла;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| ПрофилиРоли.Ссылка.Наименование КАК Профиль,
| ПрофилиРоли.Роль.Имя КАК Роль,
| ЕСТЬNULL(ГруппыДоступа.Наименование, """") КАК ГруппаДоступа
|ИЗ
| Справочник.ПрофилиГруппДоступа.Роли КАК ПрофилиРоли
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ГруппыДоступа КАК ГруппыДоступа
| ПО ПрофилиРоли.Ссылка = ГруппыДоступа.Профиль
| И (НЕ ГруппыДоступа.ПометкаУдаления)
|ГДЕ
| ПрофилиРоли.Роль.ПолноеИмя В (&ПолныеИмена)
| И НЕ ПрофилиРоли.Ссылка.ПометкаУдаления
|
|УПОРЯДОЧИТЬ ПО
| Профиль,
| ГруппаДоступа";
Запрос.УстановитьПараметр("ПолныеИмена", ПолныеИмена);
Строки = Новый Массив;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Строки.Добавить(СтрШаблон("Профиль «%1» (роль %2), группа доступа: %3",
Выборка.Профиль, Выборка.Роль,
?(ПустаяСтрока(Выборка.ГруппаДоступа), "групп нет", "«" + Выборка.ГруппаДоступа + "»")));
КонецЦикла;
Если Строки.Количество() = 0 Тогда
Возврат "Этих ролей нет ни в одном профиле: нужен свой профиль или своя роль.";
КонецЕсли;
Возврат СтрСоединить(Строки, Символы.ПС);
КонецФункции
Передайте массив ИменаРолей из первой функции во вторую. Нашлась группа, участники которой работают с теми же данными, — включите сотрудника в неё. Право есть только в широких профилях или в профилях чужих отделов — это повод для своей роли.
«Полные права» открывают сотруднику данные всех организаций и закупочные цены, а заодно администрирование. Ошибка при этом не исправлена, а спрятана. Своя роль нужна, когда не хватает права на объект доработки, которого нет в типовых ролях; когда нужно одно право, а типовая роль тянет за собой изменение десятка объектов; когда интеграция работает под техническим пользователем.
Роль создают в расширении, чтобы типовая осталась на поддержке, и отмечают только нужное: «Чтение» без «Изменения», для обработки — «Использование» и «Просмотр» (подробно — про роли 1С). В БСП роль добавляют в копию профиля или в отдельный профиль, без БСП — отмечают у пользователя в конфигураторе. Если право нужно только внутри одной операции, например проведение пишет в регистр, который сотруднику читать незачем, роль не выдают: запись делает код конфигурации в привилегированном режиме.
РАЗРЕШЕННЫЕ вместо роли. Без права на таблицу ключевое слово не спасёт: «Нарушение прав доступа!» останется.Роль «Полные права» даёт всё без ограничений, а права ролей складываются. Ошибка появляется только у тех, у кого нужной роли нет, поэтому воспроизводить её надо под учётной записью сотрудника.
Скорее всего, ограничение на уровне записей: списки и запросы с РАЗРЕШЕННЫЕ молча скрывают запрещённые строки. В БСП откройте в карточке пользователя отчёт «Права пользователя» (в УТ 11.4 его строит отчёт «Анализ прав доступа») и проверьте значения доступа в его группах.
Фоновое задание — под пользователем, который его запустил. Регламентное — под пользователем из свойства ИмяПользователя, а при пустом свойстве — под пользователем по умолчанию с административными правами. Значит, в упавшем регламентном задании указан пользователь с урезанным профилем. Подробнее — про регламентные и фоновые задания.
Для обработки конфигурации — роль с правами «Использование» и «Просмотр» на неё и «Чтение» на таблицы, которые она читает (их покажет функция проверки запроса). Для внешней — профиль «Открытие внешних отчетов и обработок» и те же права на данные.
Если ошибка в типовой и закрывается включением сотрудника в нужную группу доступа, справитесь сами по шагам выше. Если не хватает прав на объекты доработки или нужна запись в привилегированном режиме без «Полных прав», это задача для услуги по настройке прав доступа 1С. Опишите, кто и на каком действии получает ошибку, и разместите задачу: оценка бесплатная, ответ в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.