Схема взаимодействия компонент подсистемы аудита

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

AuditService

  • У приложения есть класс AuditService.
  • Через класс AuditService реализуются API для обращения:
    • к классу, наследующему от интерфейса IAudit, если аудит не выделен в отдельный сервис.
    • к сервису аудита AuditWinService.
  • AuditService хранит настройки приложения по аудиту, куда они загружаются в начале работы приложения.
  • При выполнении потенциально аудируемой операции сервис данных приложения сообщает об этом классу AuditService, который:
    • просматривает имеющиеся настройки аудита и принимает решение о необходимости выполнения записи аудита.
    • если аудит необходим, то в соответствующее сообщение идёт либо в IAudit, если нет отдельного сервиса аудита, либо в AuditWinService (ожидание ответа будет зависеть от настроек аудита).
  • Класс AuditService реализовывает интерфейс IAuditService, а также имеет статическое поле типа IAuditService, куда будет записана инстанция класса AuditService (это позволит вести работу как со статическим классом через обращение «AuditService.CurrentAuditService»). Все вызовы осуществляются через интерфейс (если появится потребность, то класс Audit можно легко подменить).

Схема взаимодействия компонент подсистемы аудита при наличии отдельного сервиса аудита

IAudit

  • IAudit представляет собой интерфейс для организации логики работы аудита (то есть именно класс, реализующий этот интерфейс, будет отвечать за запись данных аудита и за их вычитку).

AuditWinService

  • AuditWinService обслуживает несколько приложений и потенциально располагается на удалённой машине.
  • В конфиге AuditWinService указаны сервисы данных и строки подключения к базам данных аудита и базам данных приложения (если они разные).
  • При выполнении запроса AuditService сообщает AuditWinService имена строк соединения с базами данных приложения и аудита (сами строки соединения передаваться не будут, поскольку это не безопасно).
  • Несколько приложений не разделяют одну базу аудита.
  • AuditService взаимодействует с AuditWinService посредством WCF (AuditWinService – это название приложения-службы. Класс, наследуемый от IAudit, будет реализовывать WCF-контракт для доступа к публичным через WCF методам. Также он будет разработан с учётом того, что один сервис обрабатывает запросы от нескольких приложений.)

AsyncAuditController

  • AsyncAuditController – класс, организующий асинхронный доступ к IAudit, что позволяет отложить на некоторое время запись данных об аудите.

ServiceAuditController

  • ServiceAuditController – класс, отвечающий за взаимодействие через wcf с win-сервисом аудита AuditWinService, связанному с wcf-сервисом, реализующим интерфейс IAuditWcfServiceLibrary.

Схема взаимодействия компонент подсистемы аудита

Схема расположения классов и интерфейсов в сборках Flexberry

Для предотвращения возникновения ситуации перекрёстных ссылок в проекте решено было разместить основные интерфейсы аудита в сборке ICSSoft.STORMNET.Business.dll, куда уже входят интерфейс сервисов данных IDataService и класс SQLDataService.

Класс ICSSoft.STORMNET.Business.Audit.Audit, реализующий интерфейс IAudit, содержит в себе логику работы со сведениями аудита. Сервис аудита AuditWinService c wcf-сервисом AuditWcfServiceLibrary, поддерживающим интерфейс IAuditWcfServiceLibrary, являются контейнером для логики работы со сведениями аудита.

Схема расположения классов подсистемы аудита в сборках Flexberry и их взаимодействия

Примечание: реализация интерфейсов соответствует представленной схеме, однако в соответствии с планом на первый этап тестирование прошла только часть функционала

Отображение результатов аудита

  • Форма с информацией о сессиях пользователей (будет реализовано на втором этапе).
  • Форма просмотра данных аудита по всей системе (см. здесь).
  • Форма просмотра данных аудита по конкретному объекту (см. здесь).
  • Форма «Кто на сайте» (будет реализовано на втором этапе).

Примерный набор элементов на форме просмотра данных аудита по конкретному изменению:

  • Время изменения
  • Автор изменения
  • Тип операции
  • Данные по изменению:
    • для собственных полей: изменённое поле, старое значение (если его сохранение указано в настройках), новое значение.
    • для мастеров и детейлов: старое (если его сохранение указано в настройках), новое строковое представление (строковое представление по типу «поле - значение» основано на выбранном для аудита представления) и, если указано в настройках класса, старый/новый первичный ключ.
  • Элемент для вызова формы редактирования (на форме будет отображено текущее состояние объекта; если объект уже удалён, то просмотреть его состояние не удастся).
  • Элементы аудита объекта:
    • Дата создания объекта
    • Создатель объекта
    • Дата последнего изменения
    • Редактор объекта (последний)

Касательно сохраняемых значений полей следует сделать замечание, что настройки аудита позволят определить:

  • Сохранять ли в записи старое значение поля аудируемого объекта.
  • Следует ли обрезать строку с соответствующим значением поля аудита при сохранении сведений и до какой длины.
  • Следует ли сжимать значения поля аудита при сохранении и разархивировать при отображении (будет реализовано на третьем этапе).

Хранение данных аудита

Структура для хранения данных аудита

  • Для хранения данных аудита можно использовать структуру, аналогичную представленной ниже (такую структуру возможно использовать вне базы данных приложения; названия соответствующих таблиц будут иметь префикс STORM).
    • Классы Agent и LinkGroup – классы из подсистемы полномочий.
    • Интеграция с элементами системы полномочий позволит избежать хранения данных о пользователях системы в нескольких местах в разных форматах, как было ранее.
    • Использование таблиц подсистемы полномочий позволит хранить в одной БД информацию подсистемы полномочий и аудита.
    • Аналогичная структура собираемых данных позволит при необходимости проводить их интеграцию с расположенными в другой БД данными подсистемы полномочий (либо просто добавить недостающие таблицы в БД аудита, если необходимо хранить данные подсистемы полномочий в той же БД).
    • AuditSession – сведения о сессиях пользователей (аналогичный класс использовался ранее (Аудит_Сессия)):
    • StartTime – время начала сессии (например, «10.02.2013 16:00:23:123»).
    • EndTime – время окончания сессии (например, «10.02.2013 17:03:27:125»).
    • LastActionTime – время последнего аудируемого действия (например, «10.02.2013 16:30:23:123»).
    • Source – компьютер, откуда был произведён вход в приложение (например, «IP: 192.168.0.5»).
    • Enabled – активна ли сессия в настоящий момент (например, «false»).
    • Duration – продолжительность сесии (вычисляется, исходя из начала и окончания сессии; например, «0.01:03:04:002»)
    • AuditEntity – сведения об аудируемом событии над объектом (аналогичный класс использовался ранее (АудитОперации))
    • ObjectPrimaryKey – первичный ключ объекта, над которым была выполнена аудируемая операция.
    • OperationTime – время, когда над объектом была выполнена аудируемая операция.
    • OperationType – тип выполненной над объектом аудируемой операции (если была выполнена «стандартная операция», то будет передаваться в виде строки значение из типа tTypeOfAuditOperation; если была выполнена нестандартная – имя соответствующей операции).
    • ExecutionResult – результат выполнения аудируемой операции.
    • Source – компьютер, откуда была выполнена операция (например, «IP: 192.168.0.5»).
    • SerializedField – сериализованное представление данных об изменении полей из AuditFields.
    • ObjectType – тип аудируемого объекта.
    • Name – имя типа объекта (если тип стандартный, то AssemblyQualifiedName; если нестандартный – передаваемое пользователем определение).
    • AuditField – детализация по аудируемому событию над объектом: какие поля и как были изменены (аналогичный класс использовался ранее (АудитИзменения)):
    • Мастера находятся на том же уровне, что и собственные поля. Полем считается название мастера; старое и новое значения формируются в виде строки по заданному для аудита представлению. Старое и новое значение первичного ключа мастера записывается отдельной строкой и ему в качестве MainChange записывается запись об изменении мастера (отображаться изменение первичного ключа будет только если в классе наличествует соответствующая настройка).
    • Детейлы отображаются аналогично мастерам, только имена полей задаются по типу <ИмяКласса(номер)> (аналогично было сделано ранее).
  • Будет возможность хранить данные аудита как в БД приложения, так и во внешней БД. Запись данных аудита может выполняться как синхронно (то есть, пока данные по аудиту успешно не будут записаны, аудируемая операция не будет выполнена).
Синхронный доступ Асинхронный доступ
БД приложения В этом случае запись события аудита и выполнение операции [можно совместить в одной транзакции. Соответственно, если что-то пошло не так, все действия будут откачены. В этом случае в первую очередь выполняется аудируемая операция. Данные аудита отправляются отдельному процессу, который отвечает, чтобы данные аудита были в итоге записаны (возможна запись данных в некое временное хранилище).
Внешняя БД Сначала будет выполнена запись аудита (флаг Executed=false). Если запись об аудите выполнена успешно, то проводится попытка выполнить аудируемую операцию. Если аудируемая операция выполнена успешно, то в записи об аудите флаг Executed изменяется на true. В этом случае в первую очередь выполняется аудируемая операция. Данные аудита отправляются отдельному процессу, который отвечает, чтобы данные аудита были в итоге записаны (возможна запись данных в некое временное хранилище).

Структура базы данных для хранения сведений аудита

Настройка аудита

Настройка аудита в Flexberry Tool

Настройка стадии

  • В настройках стадии будет галочка «Использование аудита». Галочка учитывается при генерации приложения: если она отмечена, то дополнительные элементы (дополнительные элементы описаны в пункте «Хранение настроек»), используемые аудитом, будут генерироваться, а сама подсистема аудита приложения – функционировать.
  • В настройках стадии будет кнопка «Добавить аудит во все классы». При нажатии на кнопку все классы минимальным образом будут настроены для ведения аудита.
  • В настройках стадии можно будет выбрать, где будет располагаться БД аудита: в БД приложения или во внешней БД.

Настройка класса.

  • Для проведения аудита у класса должно быть определено представление, по которому будет вестись аудит (связывание происходит по имени представления). Для разных операций (создание, изменение, чтение, удаление) должна быть возможность задать своё представление.
  • В настройках класса будет возможность определить, для каких операций (создание, изменение, чтение, удаление) будет вестись аудит. Если отмечена хотя бы одна галочка, то дополнительные элементы (дополнительные элементы описаны в пункте «Хранение настроек»), используемые аудитом, будут генерироваться при условии, что в стадии стоит аналогичная галочка.
  • В настройках можно будет определить, следует ли использовать для аудита представление с именем по умолчанию (AuditView).
  • В настройках класса будет галочка «Дополнительные поля аудита». При выборе этой галочки в класс добавляются следующие атрибуты:
    • CreateTime (Дата создания)
    • Creator (Создатель)
    • EditTime (Дата последнего изменения)
    • Editor (Редактор)

Примечание: имя пользователя берется из Сервис текущего пользователя

  • При выборе галочки при генерации кода у класса появится наследование от интерфейса, содержащего четыре описанных поля.
  • Галочка «Дополнительные поля аудита» позволит отображать списковые формы с характерными для предыдущей версии аудита дополнительными полями. При сохранении объекта класса, где есть галочка «Дополнительные поля аудита», будет проверено, что все добавленные атрибуты присутствуют в классе (то есть не были случайно изменены/удалены), в противном случае будет брошено исключение.
  • В настройках класса можно будет выбрать вариант записи данных по аудиту: синхронный или асинхронный.

Хранение настроек

Примечание: на текущей реализации аудита используются классы: AuditAppSetting и AuditDSSetting; класс AuditClassSetting используется не в полной мере.

Общая структура для хранения настроек аудита приложения

Общие настройки аудита (AuditAppSetting)

Общие настройки аудита будут находиться в классе AuditService, куда будут вычитываться в начале работы приложения.

Общие настройки аудита (AuditAppSetting):

Настройки класса (AuditClassSetting)

Настройки класса будут генерироваться непосредственно в код класса объектов (аналогично тому, как в код класса объектов добавлен атрибут Views):

  • Включён ли аудит для класса.
  • Следует ли использовать представление по умолчанию при аудите.
  • Настройки аудита операции создания объекта (имя представления * включён ли аудит для данной операции).
  • Настройки аудита операции изменения объекта (имя представления * включён ли аудит для данной операции).
  • Настройки аудита операции чтения объекта (имя представления * включён ли аудит для данной операции).
  • Настройки аудита операции удаления объекта (имя представления * включён ли аудит для данной операции).
  • URL к форме просмотра объекта (как и в предыдущей версии подсистемы аудита через форму можно будет просмотреть текущее состояние объекта).
  • Режим записи данных аудита (синхронный или асинхронный).
  • Следует ли и насколько сильно следует обрезать сохраняемые значения аудируемых полей.
  • Отображать ли в данных аудита старое и новое значение первичного ключа мастера/детейла.
  • Следует ли в записи об изменении сохранять старое значение аудируемого поля.

В начале работы приложения настройки класса для аудита будут вычитываться в структуру AuditClassSetting:

  • ObjectType – тип объектов.
  • AuditEnabled – включён ли аудит для класса.
  • UseDefaultView – использовать для всех операций представление по умолчанию с именем «AuditView».
  • SelectAuditViewName – имя представления для ведения аудита операции чтения у класса.
  • InsertAuditViewName – имя представления для ведения аудита операции создания у класса.
  • UpdateAuditViewName – имя представления для ведения аудита операции изменения у класса.
  • ``DeleteAuditViewName` – имя представления для ведения аудита операции удаления у класса.
  • FormUrl - URL к форме просмотра объекта.
  • WriteMode – режим записи данных аудита (синхронный или асинхронный).
  • SelectAudit – дополнительно проводить аудит на чтение.
  • InsertAudit – дополнительно проводить аудит на создание.
  • UpdateAudit – дополнительно проводить аудит на изменение.
  • DeleteAudit – дополнительно проводить аудит на удаление.
  • PrunningLength – если значение больше нуля, то столько символов от значения поля, начиная с начала, будет сохраняться; если ноль, то значение будет сохраняться целиком.
  • ShowPrimaryKey – отображать ли в данных аудита старое и новое значение первичного ключа мастера/детейла.
  • KeepOldValue – нужно ли сохранять старое значение изменяемого поля.
  • Compress – следует ли сжимать сохраняемые значения полей.
  • KeepAllValues – следует ли сохранять только изменяемые поля из представления, либо все поля, входящие в представление.

Иногда возникает потребность настроить дополнительный аудит для конкретных объектов (то есть помимо того аудита, что ведётся для соответствующего класса). Например, для объектов ObjectA, ObjectB класса Class1, для которого ведётся только аудит на чтение, добавить аудит на запись.

Как это можно сделать:

  • Настройки посредством специальных команд будут задаваться в программном коде и храниться в памяти приложения во время выполнения в заданном новом формате.

Настройки для аудита объектов будут задаваться в программном коде и будут храниться в структуре AuditClassSetting и определяться полями:

  • LimitFunction – ограничение, которому должны удовлетворять объекты.
  • View – представление, по которому должны быть выгружены объекты, чтобы на них можно было накладывать ограничение.

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

В настройках класса расположены дополнительные поля (об их использовании есть информация в данной статье):

Настройки полей (AuditFieldSetting)

Настройки полей класса определяются программистом в программном коде и хранятся в структуре AuditFieldSetting:

  • FieldName – имя поля, для которого определяется настройка.
  • PrunningLength – (см. AuditClassSetting) если null, то берётся значение из соответствующего AuditClassSetting.
  • Compress – (см. AuditClassSetting) если null, то берётся значение из соответствующего AuditClassSetting.
  • KeepOldValue - (см. AuditClassSetting) если null, то берётся значение из соответствующего AuditClassSetting.
  • ``KeepAllValues - (см. AuditClassSetting) если null`, то берётся значение из соответствующего AuditClassSetting.

Настройки сервисов данных (AuditDSSetting)

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

Информация о сервисах данных, используемых приложением (AuditDSSetting):

  • DataServiceType – тип сервиса данных.
  • ConnString – строка соединения сервиса.
  • ConnStringName – имя строки соединения (имя задаётся программистом для идентификации сервиса данных; далее в конфиге сервиса аудита будет использоваться это имя).

Сервис данных, когда им была выявлена потенциально аудируемая операция, сообщает об этом классу AuditService. Если класс AuditService принял решение о том, что необходимо провести запись данных аудита, то среди отправляемой сервису аудита информации будет имя строки подключения к базе данных приложения (имя строки подключения определяется из AuditDSSetting на основании того, какой сервис данных и с какой строкой подключения обратился к классу AuditService).

Алгоритм определения актуальных настроек аудита

Схема определения, является ли операция аудируемой для класса

Если операция является аудируемой, то из найденной настройки берётся представление, после чего для собственных полей, мастеров и детейлов определяются параметры сохранения сведений аудита в следующем порядке:

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

Генерация настроек

Среди настроек аудита, определяемых в Flexberry Tool, можно выделить следующие типы:

  • Настройки стадии (общие настройки аудита для всех генерируемых со стадии приложений).
  • Настройки классов со стереотипом «application» (настройки аудита, определяемые для конкретного генерируемого приложения (на настоящий момент ASP-генератор поддерживает генерацию только одного приложения)).
  • Настройки классов со стереотипом «implementation» (настройки аудита, определяемые для конкретных классов, которые войдут в сборку объектов).

Схема генерации настроек аудита из Flexberry Tool в web-приложение*

Настройки классов со стереотипом «implementation» будут генерироваться в код объектов генератором объектов. Настройки стадии и класса со стереотипом «application» будут генерироваться в config-файл web-приложения ASP-генератором.

Чтение настроек

AuditService основные настройки классов объектов получает непосредственно из классов через reflection. Общие настройки аудита приложения загружаются в AuditService в начале работы web-приложения в Global.asax.cs, откуда идёт обращение к специализированному классу AuditSetter, который отвечает за формирование настроек из config-файла и первичную инициализацию AuditService.

Изображение

Схема чтения настроек для AuditService

Обработка ошибок

  • AuditException – базовое исключение подсистемы аудита. При выполнении таких базовых операций аудита как WriteCustomAuditOperation, RatifyAuditOperation, WriteCommonAuditOperation наружу пробрасываются только исключения такого типа.
  • DisabledAuditException – исключение сообщает, что аудит выключен, соответственно, ничего в БД аудита не попадёт.
  • DataNotFoundAuditException – не все данные, необходимые для функционирования подсистемы аудита, есть в наличии.
  • ExecutionFailedAuditException – исключение сообщает, что в ходе записи данных аудита произошло нечто, что не позволило их записать.
  • RatifyExecutionFailedAuditException – исключение сообщает, у каких именно записей аудита не удалось изменить статус.

Обычное сохранение

При обычном сохранении объектов используется метод [DataService сервиса данных) [Processing-one-object|UpdateObject) или [Processing-of-multiple-objects|UpdateObjects). В этом случае транзакция для выполнения действий над БД открывается после того, как аудит получает все требуемые для работы данные, поэтому аудит не приводит к ситуации взаимоблокировок.

Упорядоченное сохранения

При сохранении объектов с помощью метода [SQLDataService#UpdateObjectsOrdered|UpdateObjectsOrdered) транзакция открывается до того, как выполняются [Business-Servers-Wrapper-Business-Facade бизнес-серверы) и генерируются необходимые запросы. По этой причине в AuditService, который готовит данные аудита для передачи их на запись, передаётся текущая открытая транзакция, что позволяет избежать взаимоблокировок. Стоит заметить, что не принципиально, в какую именно БД и каким образом (через [AuditWinService win-сервис) или статический класс) происходит запись аудита, поскольку после передачи данных из AuditService больше не происходит обращение к БД приложения.