- Clean Architecture в Android для начинающих
- Немного теории
- Прагматичный подход
- Практическая часть — небольшое приложение для книжного каталога
- Модуль домена
- Модуль домена
- Слой данных
- Слой презентации или приложения
- Планшет и домен: единство и борьба противоположностей
- В чем основная проблема?
- В чем основная идея?
- Как это выглядит?
- Дополнительные соображения безопасности
Clean Architecture в Android для начинающих
Feb 17 · 7 min read
Даже до того, как я начал специализироваться на Android, меня, как разработчика, всегда восхищал хорошо структурированный, чистый и понятный в целом код.
“Задача архитектуры программного обеспечения — минимизация человеческих ресурсов, необходимых для создания и обслуживания требуемой системы”
Однако не всегда просто написать такой код, который легко тестировать и поддерживать, который облегчает всей команде совместную работу.
Теоретически обосновал достижение этих целей Robert Martin (он же Uncle Bob). Он написал три книги о применении «чистого» подхода при разработке программного обеспечения (ПО). Одна из этих книг называется «Чистая архитектура, профессиональное руководство по структуре и дизайну программного обеспечения (ПО )», она и явилась источником вдохновения при создании этой статьи.
Кто-то скажет, это так, но меня это не касается, ведь в моем приложении уже есть архитектура MVVM?
Что ж, возм о жно, Clean Architecture может показаться излишней в том случае, если вы работаете над простым проектом. Но как быть, если нужно разделить модули, протестировать их изолированно и помочь всей команде в работе над отдельными контейнерами кода? Подход Clean Architecture освобождает разработчиков от дотошного изучения программного кода, пытаясь понять функции и логику функционирования.
Немного теории
Вероятно, вы много раз видели эту послойную диаграмму. Правда, мне она не очень помогла понять, как преобразовать эти слои в подготовленном проекте Android. Но сначала разберемся с теорией и определениями:
· Сущности ( Entities): инкапсулируют наиболее важные правила функционирования корпоративного уровня. Сущности могут быть объектом с методами или набором из структур данных и функций.
· Сценарии использования ( Use cases): организуют поток данных к объектам и от них.
· Контроллеры, сетевые шлюзы, презентеры ( Controllers, Gateways, Presenters): все это набор адаптеров, которые наиболее удобным способом преобразуют данные из сценариев использования и формата объектов для передачи в верхний слой (обычно пользовательский интерфейс).
· UI, External Interfaces, DB, Web, Devices: самый внешний слой архитектуры, обычно состоящий из таких элементов, как пользовательские и внешние интерфейсы, базы данных и веб-фреймворки.
После прочтения этих определений я всегда оказывался в замешательстве и не был готов реализовать «чистый» подход в своих Android проектах.
Прагматичный подход
Типичный проект Android обычно требует разделения понятий между пользовательским интерфейсом, логикой функционирования и моделью данных. Поэтому, учитывая «теорию», я решил разделить свой проект на три модуля:
· Домен: содержит определения логики функционирования приложения, модели данных сервера, абстрактное определение репозиториев и определение сценариев использования. Это простой, чистый модуль kotlin (независимый от Android).
· Данные: содержит реализацию абстрактных определений доменного слоя. Может быть повторно использован любым приложением без модификаций. Он содержит репозитории и реализации источников данных, определение базы данных и ее DAO, определения сетевых API, некоторые средства преобразования для конвертации моделей сетевого API в модели базы данных и наоборот.
· Приложение (или слой представления): он зависит от Android и содержит фрагменты, модели представления, адаптеры, действия и т.д. Он также содержит указатель служб для управления зависимостями, но при желании вы можете использовать Hilt.
Практическая часть — небольшое приложение для книжного каталога
Чтобы применить на практике все эти “абстрактные” понятия, я разработал простое приложение, которое демонстрирует список книг, написанных дядей Бобом, и которое дает пользователям возможность помечать некоторые из них как “избранные”.
Модуль домена
Чтобы получить список книг, я использовал API Google книги. Это API возвращает список книг, отфильтрованных по параметру строки запроса:
В доменном слое мы определяем модель данных, сценарии использования и абстрактное определение репозитария книг. API возвращает список книг или томов с определенной информацией, такой как названия, авторы и ссылки на изображения.
data class Volume(val id: String, val volumeInfo: VolumeInfo)
Простая сущность класса данных:
Абстрактное определение репозитария книг
Сценарии использования “Get books”
Модуль домена
Чтобы получить список книг, я использовал API Google книги. Это API возвращает список книг, отфильтрованных по параметру строки запроса:
В доменном слое мы определяем модель данных, сценарии использования и абстрактное определение репозитария книг. API возвращает список книг или томов с определенной информацией, такой как названия, авторы и ссылки на изображения.
Простой объект (entity) класса данных:
data class Volume(val id: String, val volumeInfo: VolumeInfo)
Абстрактное определение репозитария книг:
Сценарии использования “Get books”:
Слой данных
Как уже отмечалось, слой данных должен реализовывать абстрактное определение слоя домена, поэтому нам нужно поместить в этот слой конкретную реализацию репозитория. Для этого мы можем определить два источника данных: «локальный» для обеспечения устойчивости и «удаленный» для извлечения данных из API.
Поскольку мы определили источник данных для управления постоянством (persistence), на этом уровне нам также необходимо определить базу данных (можно использовать Room) и ее объекты. Кроме того, рекомендуется создать несколько модулей (mappers) для сопоставления ответа API с соответствующим объектом базы данных. Помните, нам нужно, чтобы доменный слой был независим от слоя данных, поэтому мы не можем напрямую аннотировать объект доменного тома ( Volume ) с помощью аннотации @Entity room . Нам определенно нужен еще один класс BookEntity , и мы определим маппер (mapper) между Volume и BookEntity .
Слой презентации или приложения
В этом слое нам нужен фрагмент для отображения списка книг. Мы можем сохранить наш любимый подход MVVM. Модель представления принимает сценарии использования в своих конструкторах и вызывает соответствующий сценарий использования соответственно действиям пользователя (get books, bookmark, unbookmark).
Каждый сценариё использования вызывает соответствующий метод в репозитории:
Этот фрагмент только наблюдает за изменениями в модели представления и обнаруживает действия пользователя в пользовательском интерфейсе:
Теперь посмотрим, как мы выполнили связь между слоями:
Как видите, каждый слой обменивается данными только с ближними к нему, сохраняя независимость внутренних слоев от нижних. Таким образом, легче правильно определять тесты в каждом модуле, а разделение проблем поможет разработчикам совместно работать над различными модулями этого проекта.
Источник
Планшет и домен: единство и борьба противоположностей
Давайте представим себе довольно распространенный на сегодняшний день сценарий. В корпоративной сети развернуто некоторое количество бизнес-приложений. Эти приложения опубликованы для доступа снаружи по HTTPS. Мобильные сотрудники компании, находясь за пределами корпоративной сети, хотят подключаться к этим приложениям со своих личных планшетов, работающих под Windows, iOS или Android. Эти устройства либо невозможно включить в домен, либо пользователи просто не будут этого делать. Как повысить безопасность доступа с таких устройств к корпоративным приложениям? Помочь может служба регистрации устройств (Device Registration Service, DRS) в Windows Server 2012 R2.
В этой статье я сосредоточусь на основных принципах и архитектуре DRS. Детали настройки можно посмотреть в четвертом модуле курса «Корпоративные устройства. Как управлять гибридными учетными данными».
В чем основная проблема?
Внутри корпоративной сети есть веб-приложение с доступом по HTTPS, опубликованное для подключения снаружи. С любой платформы из любого браузера подключились, весь трафик между браузером и приложением шифруется, чего еще желать. Но при всех очевидных преимуществах современных мобильных устройств, планшетов в частности, есть и обратная сторона. То, что везде удобно носить с собой, легко может быть потеряно или украдено. Любой новый «владелец» устройства любопытства ради или же по злому умыслу может попытаться «поизучать» URLs в history браузера. И при сохраненных cookies, которые наверняка используются на личных устройствах, получить доступ в том числе к приложениям организации не составит труда.
В доменной сети средствами групповых политик подобных ситуаций легко избежать. Начиная с пароля для логина на доменное устройство, заканчивая сертификатами для аутентификации при доступе к приложению. Как быть с устройствами, которые в домен включить невозможно? Подходы могут быть разными: можно настроить обязательное использование пароля или PIN-кода для входа на устройство, можно сгенерировать и установить сертификат на планшет. Только для разных платформ эти процедуры отличаются, делать это придется вручную и наверняка ИТ-персоналу, и каждое новое устройство порождает соответствующую цепочку действий. А хочется, чтобы с такой задачей мог справиться владелец устройства, причем тогда, когда в этом действительно возникнет необходимость.
Одно из решений – использование DRS из состава Windows Server 2012 R2.
В чем основная идея?
Как следует из названия службы, DRS реализует процедуру регистрации устройства. В процессе регистрации DRS генерирует X.509-сертификат, который загружается на устройство, а также создает в Active Directory новый объект, содержащий информацию как об устройстве, так и пользователе, выполнившем регистрацию.
Каждый раз, когда пользователь подключается с зарегистрированного устройства к приложению, выполняется аутентификация пользователя (либо он вводит пароль, либо используется cookie) и осуществляется проверка сертификата. И только если обе проверки успешно пройдены, пользователь получает доступ к приложению. По сути мы имеем дело с двухфакторной аутентификацией.
Но важно отметить несколько моментов:
- Процедура регистрации максимально проста и не требует предварительной настройки устройства ИТ-специалистом.
- DRS поддерживает различные платформы:
- Windows 8.1 и выше
- iOS 6 и выше
- Android – Samsung KNOX
- Windows 7 Pro (включенная в домен)
- DRS не требует развертывания PKI
Как это выглядит?
В Windows Server 2012 R2 служба DRS устанавливается вместе с ADFS. ADFS, как видно из рисунков выше, играет ключевую роль в процессе аутентификации. Чтобы воспользоваться сервисом регистрации для приложения необходимо настроить аутентификацию через ADFS. Поскольку по соображениям безопасности сервер с ADFS как правило располагают внутри корпоративной сети, в зоне периметра нужна проксирующая компонента, которая будет принимать запросы из Интернет и перенаправлять их ADFS. Роль прокси может выполнять Web Application Proxy (WAP) – новая служба Windows Server 2012 R2. ADFS, в свою очередь, выполняет аутентификацию пользователя и, если настроена регистрация устройств, проверку сертификата. В случае успешной аутентификации ADFS формирует маркер (token) доступа для запрашиваемого приложения и возвращает маркер браузеру на пользовательском устройстве. После чего пользователь получает доступ к приложению.
Если говорить о требованиях к инфраструктуре, то для использования DRS необходимо расширить схему AD и иметь как минимум один сервер с Windows Server 2012 R2 и поднятой ролью ADFS.
Процесс регистрации устройства изображен на следующем рисунке.
Давайте посмотрим, как выглядит этот процесс с точки зрения владельца планшета с Windows 8.1, и что при этом происходит за кадром. В роли корпоративного приложения будет выступать SharePoint 2013. В моей инфраструктуре ADFS настроена таким образом, что регистрация устройств требуется, только если устройство находится за пределами корпоративной сети. Если же планшет подключен, например, к корпоративному Wi-Fi, то достаточно аутентификации по логину и паролю пользователя. И, конечно же, от пользователя вообще ничего не требуется, если он обращается к приложению с доменного компьютера в корпоративной сети. Имеет место полноценный Single Sign-On. Возможность настройки подобных условий доступа (conditional access), причем для конкретного приложения – еще одно серьезное преимущество использования ADFS для рассматриваемого сценария. Как задаются политики conditional access, можно посмотреть в упомянутом четвертом модуле курса «Корпоративные устройства. Как управлять гибридными учетными данными».
Итак, сотрудник компании находится за пределами компании и в браузере планшета, не включенного в домен, набирает URL корпоративного портала SharePoint. Запрос через WAP перенаправляется ADFS, и мы видим такую картину.
Как видно, элементы страницы аутентификации ADFS, равно как и страниц сообщений об ошибках (картинка, логотип, тексты сообщений), настраиваются. Пользователь указывает логин и пароль своей доменной учетной записи, причем логин вводится в формате User Principal Name (UPN). Так как устройство пока не зарегистрировано, в доступе отказано.
В тексте сообщения об ошибке я указал действия, которые необходимо совершить пользователю для регистрации планшета. Эти действия отличаются для разных платформ. Так для iOS надо просто пройти по URL: https:// /enrollmentserver/otaprofile. Для Windows 8.1 регистрация предусмотрена в интерфейсе ОС: PC Settings->Network->Workplace. И называется Workplace join.
Нажав на кнопку Join, увидим уже знакомое окно аутентификации ADFS.
Каким образом Windows 8.1 обнаруживает ADFS? Из введенного пользователем UPN берется суффикс, в данном случае, contosomsspb.com, к нему пристыковывает предопределенное имя, enterpriseregistration и получается FQDN, enterpriseregistration.contosomsspb.com, которое ОС пытается разрешить в IP. Соответственною, чтобы такой механизм обнаружения DRS работал, необходимо зарегистрировать в публичном DNS-домене организации A record с именем enterpriseregistration и IP-адресом пороксирующей компоненты, например, сервера WAP.
Если пароль введен верно, то выполняется регистрация устройства, и мы возвращаемся в предыдущее окно, где можно заметить, что операция Workplace join завершена.
Что же происходит за кадром? На самом планшете с помощью оснастки Certificates можно обнаружить появление нового сертификата.
Именно он и будет теперь использоваться в качестве второго фактора аутентификации при подключении к приложению.
В Active Directory соответствующий сертификату объект можно найти в новом контейнере RegisteredDevices. Имя объекта совпадает с CN сертификата. Атрибуты этого объекта можно посмотреть, например, с помощью ADSI Edit.
Среди атрибутов мы найдем имя устройства, тип и версию ОС, SID пользователя, выполнившего регистрацию, дату и время регистрации и др.
Пробуем снова подключиться к порталу, снова попадаем на страницу ADFS, снова вводим credentials учетной записи AD. Но теперь помимо проверки пароля успешно завершается и проверка сертификата, и доступ к приложению получен.
Более того, после первого успешного подключения пользователь получает SSO для этого приложения. Он может закрыть браузер, перезагрузить машину, открыть браузер снова, набрать URL и… получить доступ к приложению безо всяких дополнительных вопросов. Действительно, cookies обеспечивают первый фактор аутентификации, сертификат – второй. Естественно, не навечно, и периодически пользователю придется подтверждать свою аутентичность вводом пароля. Но это срок контролирует ИТ.
Дополнительные соображения безопасности
Давайте вернемся к ситуации с утерей/кражей планшета. Если устройство уже зарегистрировано, для приложения реализован SSO, и устройство попало в чужие руки. Первая линия защиты – пароль или PIN-код для входа в устройство. Для недоменных устройств обязательную блокировку можно включить, например, через Microsoft Intune или другое MDM-решение. Если этого не было сделано? Получается, мы дали злоумышленнику дополнительные козыри – ему остается просто открыть браузер и набрать URL. Очевидно, в такой ситуации владелец должен как можно быстрее оповестить свою службу ИТ. Что тогда предпримет ИТ? Посмотрим на несколько вариантов.
Если сервис регистрации устройств вообще не используется.
- Можно запретить доступ учетной записи пользователя к опубликованным приложениям. Но что, если он в длительной поездке, и ему нужен доступ к приложению с другого устройства (основного ноутбука, второго планшета и пр.)?
- Можно сбросить пользователю пароль. Но не всегда очевидно, как это отразится на доступе к другим сервисам.
Оба решения, а также другие варианты, которые можно предложить, вполне применимы, но не идеальны.
Если устройство было зарегистрировано.
Администратору достаточно найти в AD объект, ассоциированный с утерянным устройством и либо удалить объект, либо в его свойствах для атрибута msDS-IsEnabled задать значение FALSE.
Тогда при подключении к приложению сертификат устройства не пройдет проверку, и пользователь получит сообщение об ошибке. Таким образом, мы блокируем доступ конкретному устройству.
Ну а если пароль пользователя скомпрометирован и стал известен злоумышленнику? Ничто не помешает ему выполнить повторную регистрацию. Один из вариантов противодействия такому сценарию – использование сервиса многофакторной аутентификации (MFA) Microsoft Azure для регистрации устройства. В этом случае при регистрации устройства пользователю кроме ввода пароля необходимо будет пройти дополнительную проверку – ответить на входящий звонок на его мобильный телефон, либо ввести полученный по SMS код, либо использовать специальное приложение (Multi-Fator Auth), которое опять же есть в online store Microsoft, Google и Apple.
Но это уже тема отдельного разговора.
Итак, сервис регистрации устройств, появившийся в Windows Server 2012 R2, поможет обеспечить дополнительный уровень безопасности при удаленном подключении к корпоративным приложениям с личных мобильных устройств, не включенных в домен AD и работающих под управлением различных ОС.
Источник