> For the complete documentation index, see [llms.txt](https://wfsys.gitbook.io/wt-practice/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wfsys.gitbook.io/wt-practice/multiplayer_mode/lesson_access_rights.md).

# Урок 18. Права доступа

В прошлом уроке мы реализовали в программе механизм аутентификации пользователей. А также назначили права доступа группам "Администраторы" и "Пользователи". Точнее мы просто передали этим группам все права, которые были описаны для гостевой учетки, и не задали различие этих групп. Все пользователи могут смотреть и редактировать любые данные в программе.

В этом уроке мы рассмотрим статические прав доступа, а следующий урок будет посвящен динамическим правам доступа. Суть статических прав доступа заключается в том, что разработчик через серверный xml-файл настраивает разрешения для групп пользователей. Динамические права доступа позволяют пользователю через интерфейс программы самому настраивать права доступа.

{% hint style="success" %}
Если хотите начать практику с этого урока, то вам необходимо развернуть учебный проект по инструкции в статье [Разворачивание проекта](https://wfsys.gitbook.io/workflow-technology/setting-up-dev-environment/manual-deployment-project).

При разворачивании проекта используйте backup базы данных, который можете найти в архиве из раздела [Ответы](/wt-practice/multiplayer_mode/lesson_authentication.md#answer) прошлого урока. Скопируйте папки *Forms*, *Workflow* и *Patterns* в папку с развернутым проектом, например, в папку *D:\WT\Projects\Template\Projects\1. Template*.

Инструкция по подключению шаблонов находится по [ссылке](/wt-practice/main/lesson_list_form.md#podklyuchenie-shablonov-k-proektu).
{% endhint %}

## Настройка прав доступа

Есть два направления в организации прав доступа. Первое направление заключается в настройке группам пользователей разрешений на выполнение запросов на стороне сервера. Второе направление состоит в настройке доступа к графическим элементам интерфейса и выполнению команд на клиентской части.

Управлять доступом до графических объектов на формах можно через тэги `<Visible>` и `<Enabled>` этих объектов. А проверять права доступа будем через специальный элемент [`<AccessPoint>`](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/values/access_point).

### Точки доступа на форме

Перейдем в xml-файл стартовой формы (TemplateStart.xml) и на ее примере рассмотрим точки доступа.

Первым делом для каждого элемента формы в тэги `<Visible>` и `<Enabled>` необходимо прописать AccessPoint с именем, описывающем суть действия. Например, для AdminMenuItem (Администрирование) в `<MainMenu>` добавим следующие условия видимости пунктов меню:

{% code title="TemplateStart.xml" %}

```xml
<MenuItem Name="AdminMenuItem" Type="MenuItem">
  <Title>Администрирование</Title>
  <Visible>
    <Or>
      <AccessPoint Name="UserViewAccessPoint" />
      <AccessPoint Name="SettingsViewAccessPoint" />
    </Or>
  </Visible>
  <Items>
    <MenuItem Name="UserListMenuItem" Type="MenuItem">
      <Title>Пользователи...</Title>
      <Commands>
        <Command Name="UserListFormShowCommand" />
      </Commands>
      <Visible>
        <AccessPoint Name="UserViewAccessPoint" />
      </Visible>
    </MenuItem>

    <MenuItem Name="AdministrationSeparator" Type="Separator">
      <Visible>
        <And>
          <AccessPoint Name="UserViewAccessPoint" />
          <AccessPoint Name="SettingsViewAccessPoint" />
        </And>
      </Visible>
    </MenuItem>

    <MenuItem Name="SettingsMenuItem" Type="MenuItem">
      <Title>Настройки...</Title>
      <Command Name="SettingsFormShowCommand" />
      <Visible>
        <AccessPoint Name="SettingsViewAccessPoint" />
      </Visible>
    </MenuItem>
  </Items>
</MenuItem>
```

{% endcode %}

Здесь UserViewAccessPoint будет отвечать за доступ к форме списка пользователей, а SettingsViewAccessPoint - за доступ к форме настроек.

Таким образом, мы формируем набор точек доступа, необходимых для совершения действий на форме.

Теперь необходимо создать [AccessPointDataConnection](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/dataconnections/access_point_dc), который будет с сервера получать информацию о правах доступа для текущего пользователя, и прописать в нем все точки доступа, которые расставили на объектах формы:

{% code title="TemplateStart.xml" %}

```xml
<DataConnection Name="AccessPointDataConnection" Type="AccessPointDataConnection" Assembly="DataConnections">
  <Workflow Name="Template" />
  <AccessPoints>
    <AccessPoint Name="UserViewAccessPoint" />
    <AccessPoint Name="SettingsViewAccessPoint" />
  </AccessPoints>
</DataConnection>
```

{% endcode %}

Создайте команду типа DataConnectionRefreshCommand для обновления этого DataConnection. Добавьте вызов этой команды в Execution на команды LoginFormShowCommand и ReloginFormShowCommand, чтобы стартовая форма после аутентификации пользователя обновила информацию о его правах доступа.

### Точки доступа на сервере

Перейдем в Template.xml. Здесь необходимо объявить все AccessPoint, которые используются на формах. Создадим `<AccessPoints>` на одном уровне с `<SqlQueries>` и `<Permissions>`:

{% code title="Template.xml" %}

```xml
<AccessPoints>
  <AccessPoint Name="UserViewAccessPoint" />
  <AccessPoint Name="SettingsViewAccessPoint" />
</AccessPoints>
```

{% endcode %}

Теперь необходимо эти AccessPoint распределить по Permission. Переделаем UserViewSqlQueryPermission в UserViewPermission:

{% code title="Template.xml" %}

```xml
<Permission Name="UserViewPermission">
  <AccessPoint Name="UserViewAccessPoint" />
  <SqlQuery Name="UserSelectSqlQuery" />
  <SqlQuery Name="UserByIdSelectSqlQuery" />
  <SqlQuery Name="GroupSelectSqlQuery" />
  <SqlQuery Name="UserExistsSelectSqlQuery" />
</Permission>
```

{% endcode %}

Мы удалили атрибут `Type`, чтобы перевести Permission в универсальный вид и иметь возможность объявлять AccessPoint вместе с SqlQuery.

Аналогично переделаем SettingsViewSqlQueryPermission в SettingsViewPermission:

{% code title="Template.xml" %}

```xml
<Permission Name="SettingsViewPermission">
  <AccessPoint Name="SettingsViewAccessPoint" />
  <SqlQuery Name="SettingsSelectSqlQuery" />
  <SqlQuery Name="LoadModeSelectSqlQuery" />
</Permission>
```

{% endcode %}

Теперь оставим SettingsEditRole и UserEditRole только в описании AdministratorGroup.

Переименуем BaseViewSqlQueryPermission в BaseViewPermission и добавим в него запрос SettingsSelectSqlQuery. Этот запрос предоставляет настройки, необходимые в карточке заказа для отправки счета на электронную почту клиента.

Запустите приложение и проверьте отображение пунктов меню для пользователя из группы "Администраторы" и для пользователя из группы "Пользователи".

### Как это работает

При старте формы AccessPointDataConnection отправляет запрос на сервер, движок проверяет, в какой группе находится пользователь и какие Permission доступны этой группе. В ответ на запрос сервер возвращает таблицу с одной строкой, в которой для каждого AccessPoint в DataConnection будет стоять значение True или False, в зависимости от наличия соответствующего Permission у группы текущего пользователя.

## Права доступа на просмотр и редактирование сущности

Давайте настроим права доступа к заказам. Для этого на все кнопки редактирования таблицы заказов добавим AccessPoint с соответствующими именами.

Например, на кнопку OrderAddButton добавим тэг `<Enabled>` с **OrderAddAccessPoint**. Теперь необходимо для этой кнопки включить режим DisabledMode, чтобы подсказывать пользователю, почему кнопка недоступна. Таким образом, полный синтаксис кнопки добавления заказа будет иметь вид:

{% code title="TemplateStart.xml" %}

```xml
<MyObject Name="OrderAddButton" Type="Button" Assembly="BaseControls">
  <Top>
    <Object Name="OrderDatabaseTable">
      <Property Name="Top" />
    </Object>
  </Top>
  <Left>
    <Calculate>
      <Expression>{0} + 5</Expression>
      <Items>
        <Item>
          <Object Name="OrderDatabaseTable">
            <Property Name="Right" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Left>
  <Width>40</Width>
  <Height>40</Height>
  <TabIndex>3</TabIndex>
  <Hint>Добавить запись</Hint>
  <BackgroundImage>Images\24x24\plus.png</BackgroundImage>
  <BackgroundImageLayout>Center</BackgroundImageLayout>
  <FlatStyle>Flat</FlatStyle>
  <FlatBorderSize>1</FlatBorderSize>
  <FlatBorderColor>ButtonFlatBorderColor</FlatBorderColor>
  <FlatMouseDownBackColor>ButtonFlatMouseDownBackColor</FlatMouseDownBackColor>
  <FlatMouseOverBackColor>ButtonFlatMouseOverBackColor</FlatMouseOverBackColor>
  <Commands>
    <Command Name="EmptyOrderInsertSaveCommand" />
    <Command Name="OrderAddFormShowCommand" />
  </Commands>
  <Enabled>
    <AccessPoint Name="OrderAddAccessPoint" />
  </Enabled>
  <DisabledMode>True</DisabledMode>
  <DisabledText>У вас недостаточно прав для выполнения команды.</DisabledText>
</MyObject>
```

{% endcode %}

Аналогично добавим AccessPoint для кнопок OrderEditButton и OrderDeleteButton. Все AccessPoint добавим в AccessPointDataConnection и в серверный xml-файл.

Не забудьте про Execution по условию OrderCellDoubleClickCondition, в него тоже следует добавить проверку OrderEditAccessPoint.

Добавим OrderViewAccessPoint, с его помощью будем ограничивать доступ к просмотру списка заказов на главной форме.

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

Раз мы прячем таблицу от пользователей, то должны ограничить выполнение команды OrderDataConnectionRefreshCommand на обновление данных по заказам, чтобы не происходило лишнего запроса на сервер. Для этого в описание команды добавим тэг [`<Condition>`](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/commands#condition), который ограничит выполнение команды:

{% code title="TemplateStart.xml" %}

```xml
<Command Name="OrderDataConnectionRefreshCommand" Type="DataConnectionRefreshCommand" Assembly="Commands">
  <Condition Name="OrderViewAccessPointCondition" />
  <DataConnections>
    <DataConnection Name="OrderPrimaryGetDataConnection" />
  </DataConnections>
</Command>
```

{% endcode %}

Так как в команде нельзя указать AccessPoint напрямую, то мы должны обернуть его в условие проверки:

{% code title="TemplateStart.xml" %}

```xml
<Condition Name="OrderViewAccessPointCondition" Type="EqualCondition" Assembly="Conditions">
  <Items>
    <Item>
      <AccessPoint Name="OrderViewAccessPoint" />
    </Item>
    <Item>True</Item>
  </Items>
  <DataType Type="BooleanDataType" />
</Condition>
```

{% endcode %}

В серверном xml-файле добавим OrderViewAccessPoint в `<AccessPoints>` и в OrderViewSqlQueryPermission.

## Самостоятельно <a href="#self-work" id="self-work"></a>

Добавьте AccessPoint на остальные пункты меню на главной форме. На всех остальных формах так же расставьте необходимые AccessPoint. Ограничьте доступ группы "Пользователи" к отчету по бюджету и списку удаленных заказов.

Обратите внимание:

* При настройке доступа к кнопке AddEditButton, управляющей ComboBox, проверка AccessPoint должна учитывать, в каком режиме активна кнопка - добавление или редактирование.
* На форме кассы проверка прав на редактирование кассовой операции (по кнопке и по двойному клику) должна учитывать, что при выборе оплаты заказа открывается форма заказа.

## Итоги <a href="#results" id="results"></a>

В этом уроке мы настроили права доступа для групп "Администраторы" и "Пользователи", чтобы определить их возможности в программе. Настроили разрешения не только к запросам на стороне сервера, но так же определили точки доступа (AccessPoint) к элементам графического интерфейса на формах.

В следующем уроке познакомимся с динамическими правами доступа.

## Ответы <a href="#answer" id="answer"></a>

В архиве присутствуют xml-файлы форм и серверный xml-файл, а также бэкап базы данных - с помощью файлов можете проверить себя.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th data-hidden data-type="content-ref"></th></tr></thead><tbody><tr><td>lesson18-answer.zip</td><td><a href="https://wfsys.ru/download/wt_practice_desktop_answers/lesson18-answer.zip">https://wfsys.ru/download/wt_practice_desktop_answers/lesson18-answer.zip</a></td></tr></tbody></table>
