Spring security что это
Краткий обзор Spring Security
Итак, дорогой хабраюзер, предлагаю тебе рассмотреть такие аспекты Spring Security как:
Ключевые объекты контекста Spring Security:
Позволяет получить из источника данных объект пользователя и сформировать из него объект UserDetails который будет использоваться контекстом Spring Security.
Аутентификация
(1) Пользователю будет предложено войти в систему предоставив имя (логин или email) и пароль. Имя пользователя и пароль объединяются в экземпляр класса UsernamePasswordAuthenticationToken(экземпляр интерфейса Authentication) после чего он передается экземпляру AuthenticationManager для проверки.
(2) В случае если пароль не соответствует имени пользователя будет выброшено исключение BadCredentialsException с сообщением “Bad Credentials”.
(3) Если аутентификация прошла успешно возвращает полностью заполненный экземпляр Authentication.
(4) Для пользователя устанавливается контекст безопасности путем вызова метода SecurityContextHolder.getContext().setAuthentication(…), куда передается объект который вернул AuthenticationManager.
Подключение поддержки Security для SpringFramework приложения:
Ну и конечно же сам файл с настройкой security.xml
Пояснение к коду security.xml:
Подразумевается что на странице login.jsp есть форма с action=»/j_spring_security_check» в которой содержаться input’ы для имени и пароля с name=«j_username» и name=«j_password», а также checkbox c name=»_spring_security_remember_me». Это всё специальные значения которые требует Spring Security иначе параметры просто не будут передаваться в контекст безопасности. После успешного прохождения аутентификации пользователь будет перенаправлен на страницу /index где уже применяются правила авторизации. Если не указывать форму и url в http spring-security тогда по умолчанию будет работать basic authentication или можно подключить basic authentication насильно указав в http spring-security
На url /index* доступ могут иметь пользователи с правами ROLE_USER, а также гости (все подключения которые не прошли аутентификацию получают имя guest и права ROLE_ANONYMOUS).
Доступ к url /add* имеют только пользователи с правами ROLE_USER Доступ к url /delete* только пользователи с правами ROLE_ADMIN
Также, авторизованный доступ можно прикручивать на методы, для этого в security.xml нужно добавить, следующий элемент:
Также может осуществляться проверка хешированных паролей:
Подготовка к 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
Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.
Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements
Features
Comprehensive and extensible support for both Authentication and Authorization
Protection against attacks like session fixation, clickjacking, cross site request forgery, etc
Servlet API integration
Optional integration with Spring Web MVC
Quickstart Your Project
Documentation
5.6.0 CURRENT GA | Reference Doc. | API Doc. |
5.6.1-SNAPSHOT SNAPSHOT | Reference Doc. | API Doc. |
5.5.4-SNAPSHOT SNAPSHOT | Reference Doc. | API Doc. |
5.5.3 GA | Reference Doc. | API Doc. |
5.4.10-SNAPSHOT SNAPSHOT | Reference Doc. | API Doc. |
5.4.9 GA | Reference Doc. | API Doc. |
5.3.13.BUILD-SNAPSHOT SNAPSHOT | Reference Doc. | API Doc. |
5.3.12.RELEASE GA | Reference Doc. | API Doc. |
5.2.14.BUILD-SNAPSHOT SNAPSHOT | Reference Doc. | API Doc. |
5.2.13.RELEASE GA | Reference Doc. | API Doc. |
Guides
Topics
OSS support
Free security updates and bugfixes with support from the Spring community. See VMware Tanzu OSS support policy.
Commercial support
Business support from Spring experts during the OSS timeline, plus extended support after OSS End-Of-Life.
Publicly available releases for critical bugfixes and security issues when requested by customers.
Future release
Generation not yet released, timeline is subject to changes.
About commercial support (*)
Get ahead
VMware offers training and certification to turbo-charge your progress.
Get support
Spring Runtime offers support and binaries for OpenJDK™, Spring, and Apache Tomcat® in one simple subscription.
Upcoming events
Check out all the upcoming events in the Spring community.
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 на английском языке.
REST API с использованием Spring Security и JWT
Рано или поздно каждый Java-разработчик столкнется с необходимостью реализовать защищенное REST API приложение. В этой статье хочу поделиться своей реализацией этой задачи.
1. Что такое REST?
REST (от англ. Representational State Transfer — «передача состояния представления») – это общие принципы организации взаимодействия приложения/сайта с сервером посредством протокола HTTP.
Диаграмма ниже показывает общую модель.
Всё взаимодействие с сервером сводится к 4 операциям (4 — это необходимый и достаточный минимум, в конкретной реализации типов операций может быть больше):
Получение данных с сервера (обычно в формате JSON, или XML);
Добавление новых данных на сервер;
Модификация существующих данных на сервере;
Удаление данных на сервере
Более подробно можно прочесть в остальных источниках, статей о REST много.
2. Задача
Необходимо подготовить защищенное REST приложение, доступ к которому может быть осуществлен только для авторизованного пользователя. Авторизация с передачей логина и пароля выполняется отдельным запросом, при успешной авторизации система должна сгенерировать и вернуть токен. Валидация остальных запросов должна быть осуществлена по токену.
Схема нашего приложения будет выглядеть следующим образом:
3. Технологии
Для решения используем фреймворк Spring Boot и Spring Web, для него требуется:
Авторизация и валидация будет выполнена силами Spring Security и JsonWebToken (JWT).
Для уменьшения кода использую Lombok.
4. Создание приложения
Переходим к практике. Создаем Spring Boot приложение и реализуем простое REST API для получения данных пользователя и списка пользователей.
4.1 Создание Web-проекта
Создаем Maven-проект SpringBootSecurityRest. При инициализации, если вы это делаете через Intellij IDEA, добавьте Spring Boot DevTools, Lombok и Spring Web, иначе добавьте зависимости отдельно в pom-файле.
4.2 Конфигурация pom-xml
После развертывания проекта pom-файл должен выглядеть следующим образом:
Должен быть указан parent-сегмент с подключенным spring-boot-starter-parent;
И установлены зависимости spring-boot-starter-web, spring-boot-devtools и Lombok.
4.3 Создание ресурса REST
Разделим все классы на слои, создадим в папке com.springbootsecurityrest четыре новые папки:
model – для хранения POJO-классов;
repository – в полноценных проектах используется для взаимодействия с БД, но т.к. у нас ее нет, то он будет содержать список пользователей;
service – слой сервиса, прослойка между контролером и слоем ресурсов, используется для получения данных из ресурса, их проверки и преобразования (если это необходимо);
rest – будет содержать в себе классы контроллеры.
В папке model создаем POJO класс User.
В папке repository создаём класс UserRepository c двумя методами:
getByLogin – который будет возвращать пользователя по логину;
getAll – который будет возвращать список всех доступных пользователей. Чтобы Spring создал бин на основании этого класса, устанавливаем ему аннотацию @Repository.
В папке service создаем класс UserService. Устанавливаем классу аннотацию @Service и добавляем инъекцию бина UserRepository. В класс добавляем метод getAll, который будет возвращать всех пользователей и getByLogin для получения одного пользователя по логину.
Создаем контроллер UserController в папке rest, добавляем ему инъекцию UserService и создаем один метод getAll. С помощью аннотации @GetMapping указываем адрес контроллера, по которому он будет доступен клиенту и тип возвращаемых данных.
Запускаем приложение и проверяем, что оно работает, для этого достаточно в браузере указать адрес http://localhost:8080/users, если вы все сделали верно, то увидите следующее:
5. Spring Security
Простенькое REST API написано и пока оно открыто для всех. Двигаемся дальше, теперь его необходимо защитить, а доступ открыть только авторизованным пользователям. Для этого воспользуемся Spring Security и JWT.
Spring Security это Java/JavaEE framework, предоставляющий механизмы построения систем аутентификации и авторизации, а также другие возможности обеспечения безопасности для корпоративных приложений, созданных с помощью Spring Framework.
JSON Web Token (JWT) — это открытый стандарт (RFC 7519) для создания токенов доступа, основанный на формате JSON. Как правило, используется для передачи данных для аутентификации в клиент-серверных приложениях. Токены создаются сервером, подписываются секретным ключом и передаются клиенту, который в дальнейшем использует данный токен для подтверждения своей личности.
5.1 Подключаем зависимости
Добавляем новые зависимости в pom-файл.
5.2 Генерация и хранения токена
Начнем с генерации и хранения токена, для этого создадим папку security и в ней создаем класс JwtTokenRepository с имплементацией интерфейса CsrfTokenRepository (из пакета org.springframework.security.web.csrf).
Интерфейс указывает на необходимость реализовать три метода:
Генерация токена в методе generateToken;
Сохранения токена – saveToken;
Получение токена – loadToken.
Генерируем токен силами Jwt, пример реализации метода.
Параметр secret является ключом, необходимым для расшифровки токена, оно может быть постоянным для всех токенов, но лучше сделать его уникальным только для пользователя, например для этого можно использовать ip-пользователя или его логин. Дата exp является датой окончания токена, рассчитывается как текущая дата плюс 30 минут. Такой параметр как продолжительность жизни токена рекомендую вынести в application.properties.
Токен будет генерироваться новый на каждом запросе с жизненным циклом в 30 минут. После каждого запроса на фронте необходимо перезаписывать токен и следующий запрос выполнять с новым. Он станет невалидным только в том случае, если между запросами пройдет более 30 минут.
Сохранение токена выполняем в response (ответ от сервера) в раздел headers и открываем параметр для чтения фронта указав имя параметра в Access-Control-Expose-Headers.
Добавляем к классу еще один метод по очистке токена из response, будем использовать его при ошибке авторизации.
5.3 Создание нового фильтра для SpringSecurity
Создаем новый класс JwtCsrfFilter, который является реализацией абстрактного класса OncePerRequestFilter (пакет org.springframework.web.filter). Класс будет выполнять валидацию токена и инициировать создание нового. Если обрабатываемый запрос относится к авторизации (путь /auth/login), то логика не выполняется и запрос отправляется далее для выполнения базовой авторизации.
5.4 Реализация сервиса поиска пользователя
Теперь необходимо подготовить сервис для поиска пользователя по логину, которого будем авторизовывать. Для этого нам необходимо добавить к сервису UserService интерфейс UserDetailsService из пакета org.springframework.security.core.userdetails. Интерфейс требует реализовать один метод, выносить его в отдельный класс нет необходимости.
Полученного пользователя необходимо преобразовать в класс с реализацией интерфейса UserDetails или воспользоваться уже готовой реализацией из пакета org.springframework.security.core.userdetails. Последним параметром конструктора необходимо добавить список элементов GrantedAuthority, это роли пользователя, у нас их нет, оставим его пустым. Если пользователя по логину не нашли, то бросаем исключение UsernameNotFoundException.
5.5 Обработка авторизации
По результату успешно выполненной авторизации возвращаю данные авторизованного пользователя. Для этого создадим еще один контроллер AuthController с методом getAuthUser. Контроллер будет обрабатывать запрос /auth/login, а именно обращаться к контексту Security для получения логина авторизованного пользователя, по нему получать данные пользователя из сервиса UserService и возвращать их на фронт.
5.6 Обработка ошибок
Что бы видеть ошибки авторизации или валидации токена, необходимо подготовить обработчик ошибок. Для этого создаем новый класс GlobalExceptionHandler в корне com.springbootsecurityrest, который является расширением класса ResponseEntityExceptionHandler с реализацией метода handleAuthenticationException.
Метод будет устанавливать статус ответа 401 (UNAUTHORIZED) и возвращать сообщение в формате ErrorInfo.
5.7 Настройка конфигурационного файла Spring Security.
Все данные подготовили и теперь необходимо настроить конфигурационный файл. В папке com.springbootsecurityrest создаем файл SpringSecurityConfig, который является реализацией абстрактного класса WebSecurityConfigurerAdapter пакета org.springframework.security.config.annotation.web.configuration. Помечаем класс двумя аннотациями: Configuration и EnableWebSecurity.
Реализуем метод configure(AuthenticationManagerBuilder auth), в класс AuthenticationManagerBuilder устанавливаем сервис UserService, для того что бы Spring Security при выполнении базовой авторизации мог получить из репозитория данные пользователя по логину.
Реализуем метод configure(HttpSecurity http):
Разберем метод детальнее:
.authorizeRequests().antMatchers(«/auth/login»).authenticated() для запроса /auth/login выполняем авторизацию силами security. Что бы не было двойной валидации (по токену и базовой), запрос был добавлен в исключение к классу JwtCsrfFilter;
6. Проверка функционала
Для проверки использую Postman. Запускаем бэкенд и выполняем запрос http://localhost:8080/users с типом GET.
Токена нет, валидация не пройдена, получаем сообщение с 401 статусом.
Пытаемся авторизоваться с неверными данными, выполняем запрос http://localhost:8080/auth/login с типом POST, валидация не выполнена, токен не получен, вернулась ошибка с 401 статусом.
Авторизуемся с корректными данными, авторизация выполнена, получен авторизованный пользователь и токен.
Повторяем запрос http://localhost:8080/users с типом GET, но с полученным токеном на предыдущем шаге. Получаем список пользователей и обновленный токен.
Заключение
В этой статье рассмотрели один из примеров реализации REST приложения с Spring Security и JWT. Надеюсь данный вариант реализации кому то окажется полезным.