# Урок 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wfsys.gitbook.io/wt-practice/multiplayer_mode/lesson_access_rights.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
