Дискретный доступ#

Дискретный доступ позволяет выдавать привилегии в рамках объектов классов или записей в администрируемой выборке.

Настройка привилегии#

Административный объект#

  1. Открыть карточку Адм. объекта

  2. Установить признак Дискретный доступ

  3. Перейти на закладку Дискретные ограничения доступа

  4. Создать Дискретное ограничение.

Дискретное ограничение доступа#

  1. Создать новую запись или встать на запись для редактирования

  2. Указать уникальное в рамка адм. объекта имя и наименование

  3. Настроить тип правила

  4. Настроить параметры правила.

  5. На закладке Скрипт для фильтрации объектных привилегий написать sql-запрос, который будет фильтровать списки объектов

  6. На закладке Скрипт проверки строк по объектному кешу написать jexl-скрипт, который будет по rop-у объекта или строке выборки возвращать признак, что условие выполнилось для этого объекта.

Тип правила#

Доступны 3 варианта типа правила:

  • Примитивное

  • Составное

  • Без параметров

Примитивное правило#

Состоит из одного параметра.

При анализе прав пользователя со всех его ролей будут собраны значения параметров и собраны в один массив примитивных значений. Например для числового правила будет собран массив вида: [10, 20, 30]

Составное правило#

Состоит из нескольких параметров.

При анализе прав пользователя используется следующий алгоритм:

  1. Для каждого набора значений, указанных на роли, формируется json-объект вида:

    {
      <ИД параметра 1>: [<Массив указанных значений>],
      <ИД параметра 2>: [<Массив указанных значений>],
      ...
      <ИД параметра n>: [<Массив указанных значений>]
    }
    
  2. Каждая роль может обладать несколькими наборами значений на одно правило. По этому результатом агрегации настроенных значений на роли будет массив, содержащий объекты, указанные в п.1:

    [
      {json-объект для набора 1}, 
      {json-объект для набора 2},
      ...
      {json-объект для набора n},   
    ]
    
  3. При агрегации прав пользователя:

    • со всех ролей анализируются массивы, описанные в п.2

    • в json-е заменяются ИД параметров на их имена

    • каждый элемент массива приводится к строке

    • собирается результирующий массив, содержащий уникальные строки.

      Таким образом исключаются дублирующие настройки на ролях.

Пример агрегации прав пользователя:

[
  {
    "paramName1": ["a", "b", "c"],
    "paramName2": [1, 2, 3]
  },
  {
    "paramName1": ["c", "d", "e"],
    "paramName2": [3, 4, 5]
  }
]
Правило без параметров#

Не содержит параметров.

При анализе прав пользователя, если хотя на одной роли будет правило без параметров, оно будет проверяться.

Параметры правила#

Позволяют настроить тип данных и ссылочность для значений, которые будут указаны на ролях.

Если правило примитивное, то у него доступен для настройки только один параметр, для составного правила доступны несколько параметров.

Скрипт для фильтрации объектных привилегий#

Используется для фильтрации списков объектов, через наложение макроса универсального фильтра &DefUniFltMacros.

Доступные макросы внутри текста скрипта:

  • (&<Имя атрибута>)
    Будет заменено на указанное имя атрибута. Например, t.id
    Для фильтрации доступны все атрибуты дата-сета выборки шапки БО.

  • (&params)
    Массив строк, в котором будут параметры, собранные со всех ролей пользователя.

  • (&CurrentUserID)
    Будет заменено на ИД текущего пользователя.

  • (&CurrentUserName)
    Будет заменено на имя текущего пользователя.

Запрос чаще всего представляет из себя exist, в котором джойнится таблица класса, и через массив значений накладываются условия фильтрации.

Скрипт проверки строк по объектному кешу#

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

Представляет из себя jexl-скрипт, который возвращает true, если объект проходит условие, и false - если не проходит.

Доступные переменные:

  • row \

    • Если адм. объект создан по классу, то в этой переменной будет rop проверяемого объекта. Это не исходный rop, а его обертка JexlRop, которая позволяет обращаться к полям объекта.

      Совет

      Для получения исходного rop воспользуйтесь следующим примером:

      //в переменной jexlRop находится объект класса JexlRop
      var rop = jexlRop.data() 
      
    • Если адм. объект создан не по классу, то здесь будет json-представление строки дата-сета выборки.

  • params
    массив значений параметров, собранных со всех ролей пользователя.

    • если правило примитивное - то будет содержать примитивы (строка или число)

    • если правило составное - то будет содержать строки, каждая из которых - json

Роль#

  1. Открыть карточку роли или выбрать ее в списке;

  2. перейти на закладку Дискретный доступ;

  3. создать новую запись, выбрав адм. объект;

  4. указать значение параметров для ограничений;

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

Ограничение доступа к объектам класса.#

Выдается через объектные привилегии с системными именами edit# и view#

Совет

Если таких привилегий нет у адм. объекта, то выполните его синхронизацию.

Дискретные ограничения применяются только, если:

  • это главная выборка адм. объекта (шапка БО);

  • это не супер-пользователь;

  • к адм. объекту приминаются настройки администрирования;

  • адм. объект имеет признак Дискретный доступ.

Определение объектов для проверки дискретных прав#

При проверке дискретных привилегий строки, в контексте которых требуется проверить наличие прав, определяются методом acRows

Алгоритм работы метода:

  1. Если выборка принадлежит классу (thisApi() != null), то для всех выделенных записей через поле первичного ключа загружаются провайдеры строк, из них через поле gidRoot_dz определяются шапки БО

  2. Если выборка не принадлежит классу (thisApi() == null), то по всем выделенным строкам собирается json-массив, содержащий на каждую строку json-объект, в котором ключ - имя атрибута, значение - значение атрибута.

Ограничение списков#

Используя значения параметров всех ролей и настроенные «Скрипты для фильтрации объектных привилегий» формируется условие ограничения и накладывается фильтрация через макрос &DefUniFltMacros.

Ограничение открытия карточек#

На открытие карточки используя значения параметров всех ролей выполняется jexl-скрипт, настроенный в Скрипт проверки строк по объектному кешу. Если у пользователя нет прав на объект, то будет выдана ошибка.

Ограничение на редактирование объектов#

На beforeEdit или delete проверяется наличие привилегии edit# (выполняется jexl-скрипт, настроенный в Скрипт проверки строк по объектному кешу). Если у пользователя нет прав на объект, то будет выдана ошибка.

Ограничение на объектные привилегии#

Если для объектной привилегии указано Ограничение дискретного доступа, то такая привилегия может быть проверена только в контексте какого-либо объекта. Для проверки объектных привилегий используется метод Btk_AdminPkg().hasObjPriv.

Пример:

if (Btk_AdminPkg().hasObjPriv("SomeObjectName", "SomePrivName", Seq(rop))) {
   //код, выполняемый при наличии привилегии
}

Если для привилегии, имеющей ограничение, выполнить проверку без передачи объектов, то будет выдана ошибка.

Ограничение на элементарные привилегии#

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

На загрузку выборки или перезагрузку ClassLoader-а происходит подписка на событие выполнения операции.

При выполнении операции проверяются дискретные права на эту элементарную привилегию:

  1. Получение acRows

  2. Для полученных строк выполняется jexl-скрипт, настроенный в Скрипт проверки строк по объектному кешу

  3. Если прав нет, то выдается ошибка.

Примеры скриптов#

Примитивное правило по атрибуту класса#

Правило значимое, тип данных строка. Фильтрация по like атрибута sCode

Скрипт для фильтрации объектных привилегий:

select 1
  from RplTst_ClassTree tt
  join (
     select cast(json_array_elements_text(cast((&params) as json)) as varchar) as sCode
      )  as codes 
   on tt.sCode like codes.sCode
where tt.id = (&id)

Скрипт проверки строк по объектному кешу:

for (p: params) {
  if (row.sCode != null && p != null) {
    if (like(row.sCode, p)) {
     return true;
    }
  }  
}

Примитивное правило по атрибуту коллекции#

Правило ссылочное на Btk_Group. Фильтрация по прямому вхождению объекта в группу (фильтрация коллекции Btk_ObjectGroup).

Скрипт для фильтрации объектных привилегий:

select 1
  from Rpltst_TestGroup tt
  join Btk_ObjectGroup og
    on tt.gid = og.gidSrcObject
  join (
     select cast(json_array_elements_text(cast((&params) as json)) as int8) as id
      )  as params
   on og.idGroup = params.id
where tt.id = (&id)

Скрипт проверки строк по объектному кешу:

for (p: params) {
  var rops = toJRops(Btk_ObjectGroupApi.byParent(row.data())).asList();
  if (p != null) {
    for (r: rops) {
      if (r.idGroup == p) {
        return true;
      }
    }
  }  
}

Примитивное правило по адм. объекту, созданному не по классу (произвольная выборка)#

Правило значимое, тип данных строка. Фильтрация регистронезависимая по like поля sClass

Скрипт для фильтрации объектных привилегий:

select 1
   from json_array_elements_text(cast((&params) as json)) as p
  where upper((&sClass)) like upper(p)

Скрипт проверки строк по объектному кешу:

for (p: params) {
  if (row.sClass != null && p != null) {
    if (like(row.sClass.toUpperCase(), p.toUpperCase())) {
     return true;
    }
  }  
}

Составное правило по 3 атрибутам класса#

Параметры правила:

  1. dDate - Значимый, тип данных дата.

  2. nNumber - Значимый, тип данных число

  3. sCaption - Значимый, тип данных строка

Фильтрация отбирает записи у которых дата меньше указанной, число равно указанному, и Наименование по like регистронезависимо совпадает с указанной

Скрипт для фильтрации объектных привилегий:

select 1
  from RplTst_AllDbTypes tt
 where tt.id = (&id) 
   and exists (
    select 1
      from (
        select v -> 'dDate' as dDate
              ,v -> 'nNumber' as nNumber
              ,v -> 'sCaption' as sCaption
          from json_array_elements(cast((&params) as json)
            ) as v 
        ) p 
      where exists (
        select 1
          from json_array_elements_text(p.dDate) pp 
          where tt.dDate <= to_timestamp(pp, 'DD.MM.YYYY HH24:MI:SS')  
      )
        and exists (
        select 1
          from json_array_elements_text(p.nNumber) pp 
          where tt.nNumber = cast(pp as numeric) 
      )  
        and exists (
        select 1
          from json_array_elements_text(p.sCaption) pp 
          where upper(tt.sCaption) like upper(pp) 
      )  
   )

Скрипт проверки строк по объектному кешу:

for (p: params) {
  var jObj = toJObject(p);
  var res = true

  //проверка даты
  if (res) {
    res = false
    var aValues = jObj.childJArray("dDate");
    var i = 0
    while(i < aValues.size() && !res) {
      var value = aValues.getDate(i);
      if (row.dDate <= value) {
        res = true;
      }
      i = i + 1;
    }
  }

  //проверка числа
  if (res) {
    res = false
    var aValues = jObj.childJArray("nNumber");
    var i = 0
    while(i < aValues.size() && !res) {
      var value = aValues.getNumber(i);
      if (row.nNumber == value) {
        res = true;
      }
      i = i + 1;
    }
  }

  //проверка наименования
  if (res) {
    res = false
    var aValues = jObj.childJArray("sCaption");
    var i = 0
    while(i < aValues.size() && !res) {
      var value = aValues.getString(i);
      if (row.sCaption != null && value != null) {
        if (like(row.sCaption.toUpperCase(), value.toUpperCase())) {
          res = true;
        }
      }  
      i = i + 1;
    }
  }

  if (res) {
    return true;
  }

}

Составное правило по атрибуту класса и коллекции#

Параметры правила:

  1. sCaption - Значимый, тип данных строка

  2. idGroup - ссылочный на Btk_Group

Фильтрация отбирает записи, у которых Наименование по like регистронезависимо совпадает с указанным, и есть прямое вхождение в группу (фильтрация коллекции Btk_ObjectGroup).

Скрипт для фильтрации объектных привилегий:

select 1
  from RplTst_TestGroup tt
 where tt.id = (&id) 
   and exists (
     select 1
     from (
       select v -> 'sCaption' as sCaption
             ,v -> 'idGroup' as idGroup
         from json_array_elements(cast((&params) as json)) as v 
       ) p
     where exists (
       select 1
         from json_array_elements_text(p.sCaption) pp 
         where upper(tt.sCaption) like upper(pp) 
     )
       and exists (
         select 1
           from Btk_ObjectGroup og
           join json_array_elements_text(p.idGroup) pp 
             on og.idGroup = cast(pp as int8)
           where og.gidSrcObject = tt.gid
       )
   )

Скрипт проверки строк по объектному кешу:

for (p: params) {
  var jObj = toJObject(p);
  var res = true

  //проверка наименования
  if (res) {
    res = false
    var aValues = jObj.childJArray("sCaption");
    var i = 0
    while(i < aValues.size() && !res) {
      var value = aValues.getString(i);
      if (row.sCaption != null && value != null) {
        if (like(row.sCaption.toUpperCase(), value.toUpperCase())) {
          res = true;
        }
      }  
      i = i + 1;
    }
  }

  //проверка группы
  if (res) {
    res = false
    var rops = toJRops(Btk_ObjectGroupApi.byParent(row.data())).asList();
    var aValues = jObj.childJArray("idGroup");
    var i = 0
    while(i < aValues.size() && !res) {
      var value = aValues.getLong(i);
      for (r: rops) {
        if (r.idGroup == value) {
          res = true;
        }
      }
      i = i + 1;
    }
  }

  if (res) {
    return true;
  }

}

Составное правило по 2 атрибутам адм. объекта, созданного не по классу (произвольная выборка)#

Параметры правила:

  1. sClass - Значимый, тип данных строка

  2. idRefClass - ссылочный на Btk_Class

Фильтрация отбирает записи, у которых поле sClass по like регистронезависимо совпадает с указанным, и поле idRefClass совпадает с указанным

Скрипт для фильтрации объектных привилегий:

select 1
   from (
     select v -> 'sClass' as sClass
          ,v -> 'idRefClass' as idRefClass
       from json_array_elements(cast((&params) as json)) as v 
    ) p
  where exists (
      select 1
        from json_array_elements_text(p.sClass) pp 
       where upper((&sClass)) like upper(pp) 
    )   
    and exists (
      select 1
        from json_array_elements_text(p.idRefClass) pp 
       where (&idRefClass) = cast(pp as int8) 
    )   

Скрипт проверки строк по объектному кешу:

for (p: params) {
  var jObj = toJObject(p);
  var res = true

  //проверка sClass
  if (res) {
    res = false
    var aValues = jObj.childJArray("sClass");
    var i = 0
    while(i < aValues.size() && !res) {
      var value = aValues.getString(i);
      if (row.sClass != null && value != null) {
        if (like(row.sClass.toUpperCase(), value.toUpperCase())) {
          res = true;
        }
      }  
      i = i + 1;
    }
  }

  //проверка idRefClass
  if (res) {
    res = false
    var aValues = jObj.childJArray("idRefClass");
    var i = 0
    while(i < aValues.size() && !res) {
      var value = aValues.getLong(i);
      if (row.idRefClass == value) {
        res = true;
      }
      i = i + 1;
    }
  }

  if (res) {
    return true;
  }

}