Что такое spring security
Подготовка к Spring Professional Certification. Spring Security
Эта статья является переводом статьи по подготовке к Spring Professional Certification.
В ней будет рассмотрена тема Spring Security и основные вопросы по ней.
Ее также можно использовать для подготовки к собеседованию.
↓ Остальные статьи доступны по ссылкам в оглавлении ↓
Аутентификация — процесс верификации пользователя компьютерной системы.
Вот как он происходит в Spring:
Авторизация — это процесс удостоверения в том, что у пользователя есть роль, требуемая чтобы сделать какое-либо действие. При авторизации проверяется, есть ли у вас соответствующие права на доступ к ресурсу.
Сначала происходит аутентификация, а потом — авторизация.
Используя Spring AOP proxy, которые наследуются от класса AbstractSecurityInterceptor.
Применяется для методов вызывающих авторизацию.
Веб-инфраструктура в Security основана на servlet-фильтрах.
SeccurityFilterChain сравнивает URL в запросе со списком фильтров.
SecurityContextHolder — содержит и предоставляет доступ к SecurityContext в приложении.
SecurityContext — дефолтная реализация Spring Security содержащая объект Authentication.
Authentication — предоставляет токен для запроса аутентификации или для принципала, который прошел аутентификацию. Также содержит список полномочий, к которым получил доступ принципал.
GrantedAuthority — содержит полномочия выданные прошедшему проверку принципалу.
UserDetails — содержит информацию о пользователе: пароль, логин, полномочия. Эта информация используется для создания объекта Authentication после удачной аутентификации.
UserDetailsService — этот сервис извлекает информацию о пользователе из хранилища(память программы, бд, и т.п.) и кладет ее в UserDetails.
Это специальный фильтр, который делегирует работу другим бинам, которые также являются фильтрами.
Конструктор DSFC принимает несколько параметров. Первый параметр — request matcher. Остальные параметры — это фильтры, реализующие интерфейс servlet.Filter. Вот все фильтры, принимаемые DSFC:
Authentication представляет следующие свойства:
Это выражение означает “любой”.
* — перехватывает только на том уровне, на котором используется.
Например, паттерн “/orders/*” проверит права пользователя, если пользователь перейдет по
/orders/aliens или /orders/1, но не /orders/alien/1.
** — перехватывает на всех уровнях.
Будут проверены любые запросы, /orders/aliens, /orders/1, /orders/alien/1.
Соль используется для вычисления хеш-значения пароля. Это последовательность рандомных чисел, которые используются для преобразования текстового пароля в хеш. Соль хранится в открытом виде рядом с хеш-паролем и может использоваться в дальнейшем при конвертации чистого пароля в хеш при новом логине пользователя.
Spring Security поддерживает защиту отдельных методов в бинах(например, в контроллерах). Это дополнительный слой защиты для приложения.
Эта аннотация основана на JSR-250.
@RolesAllowed позволяет настроить доступ к методам(например, в классе-контроллере) с помощью ролей.
Пример: @RolesAllowed(“ADMIN”) будет пропускать только пользователей с ролью ADMIN
Для использования нужно установить @EnableGlobalMethodSecurity(jsr250Enabled=true) на @Configuration классе + нужно чтобы эта аннотация была в classpath.
@PreAuthorize позволяет настроить доступ к методу используя SpEL.
Для использования нужно установить @EnableGlobalMethodSecurity(prePostEnabled=true)
Используется сквозная функциональность, с помощью Spring AOP(прокси-объекты).
Spring Security Hello World Java Config
В этом материале мы постараемся написать приложение защищенное Spring Security с применением Java Config (подхода на основе использования аннотаций и классов для настройки контекста Spring приложения) вместо XML.
Используемые Технологии
Это будет очень простое веб приложение, Hello World на базе Spring MVC и Spring Security. Все настройки мы осуществим используя только Java классы, без единой строчки конфигурации в XML.
Начнем с рассмотрения структуры проекта.
Структура Проекта.
Зависимости Maven (из pom.xml)
Далее мы рассмотрим настройку контроллерa Spring MVC.
Контроллер ( AppController.java )
Настраиваем Spring MVC (WebConfig.java)
Необходимо указать фреймворку Spring где находятся компоненты представления, и как их отображать. Так же надо привязать настройки безопасности. Все это можно сделать с помощью Java класса с аннотацией @Configuration (в будущем мы будем называть такие классы конфигурационными).
Настройки Безопасности (Spring Security — AppSecurityConfig.java, SecurityInit.java)
Для тех кто знаком с XML конфигурацией, выше приведенный код аналогичен следующему:
Мы закончили настройку MVC и Spring Security. Осталось настроить Диспетчер Сервлета, который отвечает за инициализацию Spring MVC и меппинг URL паттернов. Опять же мы откажемся от традиционной настройки Диспетчера Сервлета через web.xml и будем использовать Java Классы.
Настраиваем Диспетчер Сервлета (WebAppInitializer.java)
Здесь мы настроили мэпинг сервлета на “/” и поэтому все запросы будут перехвачены Диспетчером Сервлета Spring.
Представления (Вьюшки)
Тут можно толко отметить, что ссылка на logout URL: logout и что по умолчанию тип logout запроса должен быть POST и запрос logout должен содержать csrf token.
Spring Security, сам сгенерирует страницу login.
Финиш.
Как мы и хотели ресурс /helloworld незащищен
Когда же мы поменяем URL на http://localhost:8080/sshwa/protected/ Spring Security перенаправит нас на /login, с формой аутентификации по умолчанию. Если мы введем неверные логин или пароль, будут отображены сообщения об ошибках, и Spring сделает редирект на URL /login?error.
Для неавторизированных пользователей Spring сначала выкинет нас в root («/»), а при следующей попытке зайти на ресурс с неподходящей ролью, отобразит страничку с кодом 403.
Надеюсь в будущем у меня будет время чтобы постепенно развивать этот туториал (в планах перевести все на Spring Boot, а когда выйдет Spring Security 4.0 Release попытаться прикрутить тесты).
На основе материала из источника: javahash.com/spring-security-hello-world-example. Код переработан, текст дополнен кажущимися мне полезными комментариями.
Это мой первый материал, постараюсь учесть все пожелания и замечания.
Spring Security/Технический обзор Spring Security
Эта статья представляет собой перевод Spring Security Reference Documentation, Ben Alex, Luke Taylor 3.0.2.RELEASE, Глава 5, Технический обзор.
Содержание
Среда исполнения [ править ]
Для Spring Security 3.0 требуется среда исполнения Java 5.0 или выше. Т.к. Spring Security стремится работать автономно, то нет никакой необходимости размещать специальные файлы-конфигурации в Java Runtime Environment. В частности, нет необходимости специально настраивать файл политики Java Authentication and Authorization Service (JAAS) или помещать Spring Security в общий CLASSPATH.
Аналогичным образом, если вы используете EJB контейнер или контейнер сервлета, то нет необходимости создавать где-либо специальные конфигурационные файлы или включать Spring Security в загрузчик классов сервера. Все необходимые файлы будут содержаться в вашем приложении.
Такая конструкция обеспечивает максимальную гибкость во время развертывания, так как вы можете просто скопировать целевой артефакт (JAR, WAR или EAR) из одной системы в другую, и он будет работать.
Ключевые компоненты [ править ]
В Spring Security 3.0, содержимое jar-файла spring-security-core было урезано до минимума. Он не содержит никакого кода, связанного с безопасностью веб-приложений, LDAP или конфигурирования с помощью пространства имен. Здесь мы рассмотрим некоторые Java типы, которые можно найти в основном модуле. Они представляют собой строительные блоки каркаса. Так что если вам когда-нибудь понадобится выйти за рамки простой конфигурации пространства имен, то важно чтобы вы понимали что они собой представляют, даже если вам не потребуется взаимодействовать с ними напрямую.
Объекты SecurityContextHolder, SecurityContext и Authentication [ править ]
Получение информации о текущем пользователе [ править ]
Внутри SecurityContextHolder мы храним информацию о доверителе, взаимодействующим в настоящее время с приложением. Spring Security использует объект Authentication для представления этой информации. Как правило нет необходимости создавать объект Authentication самостоятельно, но запросы к объекту Authentication довольно распространенное действие. Вы можете использовать следующий код в любом месте вашего приложения, чтобы получить имя текущего зарегистрированного пользователя, например:
Сервис UserDetails [ править ]
Это наиболее общий подход к загрузке информации о пользователе в Spring Security и вы увидите, что это используется в каркасе когда требуется информация о пользователе.
GrantedAuthority [ править ]
Резюме [ править ]
Просто напомним, основными блоками Spring Security являются:
Теперь, когда у вас есть понимание многократно используемых компонентов, давайте внимательнее рассмотрим на процесс аутентификации.
Аутентификация [ править ]
Spring Security можно использовать в самых разных средах аутентификации. Хотя мы рекомендуем использовать Spring Security для аутентификации, а не интегрировать ее с существующей Container Managed Authentication, хотя этот механизм и поддерживается. То же касается и интеграции с вашей собственной системой аутентификации.
Что представляет собой аутентификация в Spring Security [ править ]
Рассмотрим стандартный сценарий аутентификации с которым все хорошо знакомы.
Пользователь перенаправляется на выполнение операций, которые могут быть защищены механизмом контроля доступа, который проверяет необходимые разрешения для выполнения операций на основании информации текущего контекста безопасности.
Первые три пункта составляют непосредственно процесс аутентификации, поэтому мы рассмотрим, как это происходит в Spring Security.
С этого момента пользователь считается подлинным. Давайте рассмотрим код в качестве примера.
Установка содержимого SecurityContextHolder напрямую [ править ]
Аутентификация в Веб-приложениях [ править ]
Теперь давайте исследуем ситуацию, где вы используете Spring Security в веб-приложении (система безопасности в web.xml выключена). Как аутентифицируется пользователь и устанавливается контекст безопасности приложения?
Рассмотрим типичный процесс аутентификации веб-приложения
ExceptionTranslationFilter [ править ]
AuthenticationEntryPoint [ править ]
Механизм аутентификации [ править ]
Сохранение SecurityContext между запросами [ править ]
Многие другие типы приложений(например, RESTful веб-сервисы без сохранения состояния) не используют HTTP сессии и будут требовать аутентификации при каждом запросе. Тем не менее, все равно очень важно, чтобы SecurityContextPersistenceFilter входил в цепочку, чтобы SecurityContextHolder очищался после каждого запроса.
Управление доступом (Авторизация) в Spring Security [ править ]
Безопасность и Советы AOP [ править ]
Если вы хорошо знакомы с AOP, то должны знать что существуют различные виды советов: before, after, throws и around. Совет around очень полезен, потому что советчик может выбирать, следует или нет осуществить вызов метода, следует или нет изменить отклик, следует или нет пробросить исключение. Spring Security предоставляет around советы как для вызова методов, так и для веб-запросов. Для вызова методов совет around реализуется с помощью стандартного AOP модуля Spring’а, а для веб-запросов с помощью стандартного фильтра.
Для тех, кто не знаком с AOP, главное понять, что Spring Security может защищать вызовы методов так же хорошо, как и веб-запросы. Для большинства людей важно обеспечить безопасность вызова методов на уровне сервисов. Потому что на уровне сервисов сосредоточено большинство бизнес-логики нынешнего поколения J2EE приложений. Если вам просто нужно обеспечить безопасность при вызове методов на уровне сервисов, то стандартный Spring AOP будет весьма уместным. Если вам нужно обеспечить безопасность непосредственно объектов предметной области, то вероятно следует рассмотреть вариант использования AspectJ.
Защищенные Объекты и AbstractSecurityInterceptor [ править ]
Что такое «защищенный объект» в общем смысле? Spring Security использует этот термин для обозначения любого объекта, к которому могут применяться механизмы обеспечения безопасности (например, авторизация). Наиболее распространенными примерами являются вызовы методов и веб-запросы.
AbstractSecurityInterceptor обеспечивает последовательный рабочий процесс для обработки запросов к защищенному объекту, обычно:
Что такое конфигурационные атрибуты [ править ]
RunAsManager [ править ]
AfterInvocationManager [ править ]
AbstractSecurityInterceptor и связанные с ним объекты показаны на рисунке 5.1, «Модель перехватчиков системы безопасности и «защищенного объекта».
Расширение модели защищенного объекта [ править ]
Только те разработчики, которые рассматривают возможность создания полностью нового способа перехвата и авторизации запросов, должны напрямую использовать защищенные объекты. Например, можно было бы построить новый защищенный объект для системы обмена сообщениями. Все что требует обеспечения безопасности и обеспечивает способ перехвата вызовов (на подобие семантики AOP совета around) может быть превращено в защищенный объект. Можно сказать, что в большинстве Spring-приложений можно легко и прозрачно использовать три, в настоящее время поддержаващихся, типа защищенных объектов (MethodInvocation AOP альянса, AspectJ JoinPoint и FilterInvocation для веб-запросов).
Локализация [ править ]
Spring Security поддерживает локализацию сообщений в исключениях, которые скорее всего увидят конечные пользователи. Если ваше приложение разработано для Англоговорящих пользователей, то по умолчанию вы не должны ничего делать, все сообщения Spring Security написаны на английском языке. Если вы должны поддерживать локализацию для других языков, то все что вам нужно знать, содержится в этом разделе.
Все сообщения исключений могут быть локализованы, включая сообщения, связанные с отказом аутентификации и запрета доступа (отказы авторизации). Исключения и логи, которые предназначены для разработчиков или лиц, ответственных за развертывание приложения (включая некорректные атрибуты, нарушения контракта интерфейса, использование некорректных конструкторов, проверки во время запуска, логгирование режима отладки) и т.д., не локализуются, а вместо этого явно написаны в коде Spring Security на английском языке.
Регистрация и авторизация с помощью Spring Security на примере простого приложения
В этой статье будет рассмотрено создание простого веб приложения с использованием Spring Boot и Spring Security. В приложении будет реализована регистрация новых пользователей и авторизация, ограничение доступа к страницам сайта в зависимости от роли пользователя.
Главная цель статьи показать как можно ограничить доступ к различным страницам сайта для пользователей с разными ролями.
Что будет представлять из себя приложение
Сайт со следующими страницам:
Что будем использовать
Содержание
1. Описание основных используемых аннотаций
Controller – специальный тип класса, применяемый в MVC приложениях. Похож на обычный сервлет HttpServlet, работающий с объектами HttpServletRequest и HttpServletResponse, но с расширенными возможностями от Spring Framework.
Repository – указывает, что класс используется для задания перечня
необходимых работ по поиску, получению и сохранению данных. Аннотация может использоваться для реализации шаблона DAO.
Service – указывает, что класс является сервисом для реализации бизнес логики.
Configuration – эта аннотация используется для классов, которые определяют bean-компоненты.
Autowired – аннотация позволяет автоматически установить значение поля. Функциональность этой аннотации заключается в том, что нам не нужно заботиться о том, как лучше всего Bean’у передать экземпляр другого Bean’a. Spring сам найдет нужный Bean и подставит его значение в свойство, которое отмечено аннотацией.
Немного информации о Spring Security
Самым фундаментальным объектом является SecurityContextHolder. В нем хранится информация о текущем контексте безопасности приложения, который включает в себя подробную информацию о пользователе (принципале), работающим с приложением. Spring Security использует объект Authentication, пользователя авторизованной сессии.
«Пользователь» – это просто Object. В большинстве случаев он может быть
приведен к классу UserDetails. UserDetails можно представить, как адаптер между БД пользователей и тем что требуется Spring Security внутри SecurityContextHolder.
Для создания UserDetails используется интерфейс UserDetailsService, с единственным методом:
2. Создание нового проекта в IDE
Мы будем использовать систему сборки Maven.
Под GroupId подразумевается уникальный идентификатор компании (или ваше личное доменное имя), которая выпускает проект. ArtefactId – это просто название нашего проекта.
После завершения создания проекта отроется файл pom.xml, Idea предложит включить автоимпорт – не отказывайтесь. В этом файле будут содержаться все зависимости (библиотеки), используемые в проекте.
3. Создание структуры проекта (пакетов)
Сразу перейдем к созданию пакетов. Структура проекта, которая должна получиться показана ниже.
Теперь коротко о том, что будет храниться в каждом пакете:
Далее добавляем зависимости для работы модулей Spring, драйвер БД PostgreSQL, сервера Tomcat, JSTL.
По умолчанию maven будет использовать старую версию java 1.6, чтобы это исправить указываем версию явно.
Также добавляем плагин, позволяющий упаковывать архивы jar или war и запускать их «на месте»:
Свойство spring.jpa.show-sql выводит тела запросов к БД в консоль.
spring.jpa.hibernate.ddl-auto позволяет задать стратегию формирования БД на основе наших моделей, имеет разные значения (none, create, update и др.). update в данном случае значит, что таблицы БД и поля будут созданы на основе наших моделей и буду изменяться вместе с ними.
Забегая вперед можно отметить, что нам нужно будет только создать БД с именем spring, а таблицы пользователей, ролей и их связующая таблица вместе с внешними ключами будут сформированы автоматически на основе моделей (пакет entity), к созданию которых мы сейчас перейдем.
4. Добавление сущностей, контроллеров, сервисов, репозиториев и представлений
4.1. Добавление сущностей (моделей)
Обязательное требование для всех сущностей: приватные поля, геттеры и сеттеры для всех полей и пустой конструктор (в примерах не представлены). Их не нужно писать вручную, нажмите Alt+Insert и Idea сделает это за вас.
Для импорта необходимых классов и библиотек используем комбинацию клавиш Alt+Enter.
User. В начале об аннотациях: Entity говорит о том, что поля класса имеют отображение в БД, Table(name = «t_user») указывает с какой именно таблицей.
GenerationType.IDENTITY параметр IDENTITY значит, что генерацией id будет заниматься БД. Существует другие стратегии. SEQUENCE – использует встроенный в базы данных, такие как PostgreSQL или Oracle, механизм генерации последовательных значений (sequence). TABLE – используется отдельная таблица с проинициализированным значениями ключей. Еще один вариант – AUTO, hibernate сам выберет из одну вышеописанных стратегий, но рекомендуется указывать стратегию явно.
Поле, находящееся под аннотацией Transient, не имеет отображения в БД. Список ролей связан с пользователем отношением многие ко многим (один пользователь может иметь несколько ролей с одной стороны и у одной роли может быть несколько пользователей с другой);FetchType.EAGER – «жадная» загрузка, т.е. список ролей загружается вместе с пользователем сразу (не ждет пока к нему обратятся).
Для того, чтобы в дальнейшим использовать класс Userв Spring Security, он должен реализовывать интерфейс UserDetails. Для этого нужно переопределить все его методы. Но в нашем примере мы будем использовать только метод getAuthorities(), он возвращает список ролей пользователя. Поэтому для остальных методов измените возвращаемое значение на true.
Role. Этот класс должен реализовывать интерфейс GrantedAuthority, в котором необходимо переопределить только один метод getAuthority() (возвращает имя роли). Имя роли должно соответствовать шаблону: «ROLE_ИМЯ», например, ROLE_USER. Кроме конструктора по умолчанию необходимо добавить еще пару публичных конструкторов: первый принимает только id, второй id и name.
Здесь же можно добавить ограничения на поля. Size(min=2) – значит, что минимальная длина поля 2, в случае если ограничение нарушено будет выведено сообщение.
4.2. Реализация слоя доступа к данным и сервисного слоя
Spring Data предоставляет набор готовых реализаций для создания слоя, обеспечивающего доступ к БД. Интерфейс JpaRepository предоставляет набор стандартных методов (findBy, save, deleteById и др.) для работы с БД.
Т.о. просто создав интерфейс и унаследовав JpaRepository можно выполнять стандартные запросы к БД. Если понадобиться специфичный метод просто добавляем его в интерфейс, опираясь на подсказки Idea. Например, нам нужен метод поиска пользователя в БД по имени. Пишем тип возвращаемого объекта, а затем IDE предлагает возможные варианты. Т.е. в данном случае имя метода определяет, тело запроса.
При необходимости можно использовать аннотацию Query над методом и писать запросы на HQL или SQL (нужно добавить nativeQuery = true).
RoleRepository. Создаем аналогично, собственные методы тут не понадобятся.
UserService. Содержит методы для бизнес-логики приложения. Этот класс реализует интерфейс UserDetailsService (необходим для Spring Security), в котором нужно переопределить один метод loadUserByUsername().
В этом классе можно увидеть еще один способ выполнения SQL запроса — с помощью EntityManager.
Рассмотрим метод saveUser(User user).
Сначала происходит поиск в БД по имени пользователя, если пользователь с таким именем уже существует метод заканчивает работу. Если имя пользователя не занято, добавляется роль ROLE_USER. Чтобы не хранить пароль в «сыром» виде он предварительно хэшируется с помощью bCryptPasswordEncoder. Затем новый пользователь сохраняется в БД.
4.3. Добавление контроллеров
Для страниц, которые никак не обрабатываются сервером, а просто возвращают страницу, маппинг можно настроить в конфигурации. Страница login обрабатывается Spring Security контроллером по умолчанию, поэтому для неё отдельный контроллер не требуется.
RegistrationController. Отдельный контроллер нужен для страницы регистрации. Для обработки GET запроса используется аннотация @GetMapping(«/registration»), для POST – @PostMapping(«/registration»).
Чтобы что-то добавить или получить со страницы мы обращаемся к model. В GET запросе на страницу добавляется новый пустой объект класса User. Это сделано для того, чтобы при POST запросе не доставать данные из формы регистрации по одному (username, password, passwordComfirm), а сразу получить заполненный объект userForm.
Метод addUser() в качестве параметров ожидает объект пользователя (userForm), который был добавлен при GET запросе. Аннотация Valid проверяет выполняются ли ограничения, установленные на поля, в данном случае длина не меньше 2 символов. Если ограничения не были выполнены, то bindingResult будет содержать ошибки.
Если пароль и его подтверждение не совпадают добавляем сообщение на страницу и возвращаем её. В конце пробуем сохранить добавить пользователя в БД.
Метод saveUser() возвращает false, если пользователь с таким именем уже существует и true, если пользователь сохранен в БД. При неудачной попытке сохранения – добавляем сообщение об ошибке и возвращаем страницу. При удачном сохранении пользователя – переходим на главную страницу.
AdminController. Доступ к странице admin имеют только пользователи с ролью администратора. В методе userList() нет ничего нового, он получает данные всех пользователей и добавляет их на страницу.
Метод deleteUser() использует аннотацию RequestParam т.е. в представлении будет форма, которая должная передать два параметра – userId и action. Ссылка будет иметь вид http://localhost:8080/admin?userId=24&action=delete при выполнении такого запроса будет удален пользователь с >
Еще один вариант передать параметры в URL – использовать PathVariable. С помощью этой аннотации мы получаем отдельные части URL, для метод getUser() URL будет выглядеть следующим образом: http://localhost:8080/admin/gt/24, после перехода выведется список всех пользователей с id>24.
WebSecurityConfig. Содержит 2 бина BCryptPasswordEncoder и AuthenticationManager, которые, уже встречались ранее в классе userService.
Кроме этого в методе configure() настраивается доступ к различным ресурсам сайта. В качестве параметров метода antMatchers() передаем пути, для которых хотим установить ограничение. Затем указываем, пользователям с какой ролью будет доступна эта страница/страницы.
4.4. Добавление представлений
index.jsp Главная страница, ниже представлены 2 варианта — для гостя и для авторизованного пользователя.
Для скрытия части контента на странице для авторизованных пользователей (ссылка на страницу регистрации и авторизации) можно использовать тег authorize из библиотеки тегов Spring Security. Параметр access принимает несколько выражений, можно, например, установить ограничение в зависимости от роли пользователя hasRole(‘ADMIN’).
registration.jsp Страница регистрации.
Эту страницу, как уже говорилось, обрабатывает контроллер Spring’а по умолчанию. Важно указать действие: action=»/login» и name инпутов.
admin.jsp Страница администратора.
news.jsp Страница новостей статическая. Используется только для демонстрации прав пользователей, поэтому содержание на ваш выбор.
5. Запуск приложения
В main класс Application нужно добавить следующее:
Перед тем, как переходить к следующему шагу, убедитесь в том, что структура вашего проекта соответствует представленной в начале.
Пришло время создать пустую БД с именем spring, это нужно сделать перед первым запуском приложения и только один раз.
Можете запустить приложение и посмотреть, как измениться БД – в ней создадутся 3 пустые таблицы. Нужно добавить роли пользователей в таблицу t_role:
Теперь можно попробовать зарегистрироваться. В приложение не предусмотрено метода для регистрации пользователя-администратора, но он нужен для демонстрации. Поэтому после регистрации нового пользователя, добавьте в таблицу пользователь-роли запись, дающую эту роль:
Если после добавления прав администратора вы не можете зайти на страницу администратора (ошибка 403) – перезайдите на сайт.
К странице http://localhost:8080/admin доступ имеет только пользователь с ролью администратора. http://localhost:8080/news увидит любой зарегистрированный пользователь. Также можно попробовать перейти на страницы регистрации и логина, будучи авторизированным на сайте.
Заключение
В итоге было создано веб приложение, в котором мы можем управлять доступом пользователей к страницам сайта применяя роли. Можно назначать несколько ролей одному пользователю. Например, при регистрации нового пользователя добавляем базовую для всех роль User, а затем при запросе дополнительных привилегий пользователем можем дать ему допустим роль Writer, которая позволит ему добавлять новые новости на сайт.
Файлы css и js были созданы, но их содержимое не было представлено. При желании можно добавить дизайн, например, используя Bootstrap и интерактивности с помощью js.