Хочешь, хорошо работать пользуйся Спрингом. Хочешь, чтобы работало хорошо знай его кишки. Навигация
Скачать 4.45 Mb.
|
PasswordEncoder S pring Security не может волшебным образом угадать предпочтительный алгоритм хеширования паролей. Вот почему вам нужно указать другой @Bean, PasswordEncoder. Если вы хотите, скажем, использовать функцию хеширования паролей BCrypt (по умолчанию Spring Security) для всех ваших паролей , вы должны указать этот @Bean в своем SecurityConfig. Ч то делать, если у вас есть несколько алгоритмов хеширования паролей, потому что у вас есть несколько старых пользователей, чьи пароли хранились с помощью MD5 (не делайте этого), и более новые с помощью Bcrypt или даже третьего алгоритма, такого как SHA-256? Тогда вы должны использовать кодировщик passwordEncoder: Он будет смотреть на хешированный пароль UserDetail (из таблицы вашей БД), который теперь должен начинаться с {prefix}. Префикс - ваш метод хеширования! Как это работает в Spring Security (поэтапно): 1) Прочтите эти пароли и удалите префикс ({bcrypt} или {sha256}). 2) В зависимости от значения префикса используйте правильный PasswordEncoder (например, BCryptEncoder или SHA256Encoder). 3) Хешируйте входящий необработанный пароль с помощью PasswordEncoder и сравните его с сохранённым. Это всё, что нужно для понимания PasswordEncoders. Вывод из этого раздела: если вы используете Spring Security и имеете доступ к паролю пользователя, то: Укажите UserDetailsService. Либо пользовательская реализация, либо используйте и настройте ту, которую предлагает Spring Security. Укажите PasswordEncoder. Это и есть аутентификация Spring Security. |
Какими путями можно обеспечить секьюрность проекту? (два способа настройки аутентификации и авторизации) |
- Первый, классический способ - создать WebSecurityConfigurerAdapter и самостоятельно заняться конфигурацией, для переопределения настроек HttpSecurity объекта по умолчанию (это мы уже делали). Здесь доступны такие параметры конфигурации, как OAuth 2.0, Form Login и HTTP Basic. Это отличное место для установки глобальных настроек аутентификации. - Второй способ – использовать аннотацию @PreAuthorize к методам контроллера, она обеспечивает безопасность на уровне метода контроллера и используется для тонкой настройки. @PreAuthorize одна из набора доступных аннотаций, но наиболее часто используемая, есть ещё старая @Secured. Какие у этих двух способов отличия помимо масштабов настройки? Первое отличие неуловимое. HttpSecurity метод отклоняет запрос раньше, в фильтре веб-запроса, до того, как произошло сопоставление контроллера. Напротив, в @PreAuthorize оценка происходит позже, непосредственно перед выполнением метода контроллера, тогда, когда запрос уже прошёл фильтрацию. Это означает, что конфигурация HttpSecurity применяется раньше @PreAuthorize. Во-вторых, HttpSecurity привязан к конечным точкам URL-адреса, в то время как @PreAuthorize привязан к методам контроллера и фактически расположен в коде рядом с определениями контроллера. Наличие всей безопасности в одном месте и её определение конечными веб-точками (эндпойнты, например admin/edit/id) имеет определенную аккуратность, особенно в небольших проектах или для более глобальных настроек; однако по мере того, как проекты становятся больше, может иметь больше смысла держать политики авторизации рядом с защищаемым кодом, что позволяет метод на основе аннотаций. Третье преимущество , которое есть в @PreAuthorize это использование SPEL. Spring Expression Language позволяет принимать решения об авторизации на основе выражений, которые могут обращаться к встроенным объектам аутентификации (таким как authentication и principal), параметрам метода с введёнными зависимостями и параметрам запроса. О методах hasAuthority() и hasRole() почитайте дальше по списку. Ещё существует аннотация @PostAuthorize о которой просто нужно знать. Эта аннотация так же, как и @PreAuthorize находится на уровне метода, но авторизация проверяется не до, а после выполнения метода контроллера. Зачем нам это нужно? Это позволяет методу выполнять свои собственные проверки авторизации на основе любой логики контроллера, которая ему нравится, до получения разрешения аннотации. Метод контроллера это маленький ребёнок который спрашивает маму @PreAuthorize, можно ли ему поиграть с этой машинкой. И есть второй ребёнок, который сначала играет с машинкой, а потом мама @PostAuthorize видит это, и либо отбирает её, либо не мешает играть. Подробнее тут! |
6. Что такое AuthenticationProvider? (отсутствие доступа к паролю пользователя) |
Теперь представьте, что вы используете Atlassian Crowd для управления идентификацией. Это означает, что все ваши пользователи и пароли для всех ваших приложений хранятся в Atlassian Crowd, а не в таблице БД. То есть: 1) У вас больше нет паролей пользователей в вашем приложении, так как вы не можете попросить Crowd просто дать вам эти пароли. 2) Однако у вас есть REST API, в который вы можете войти, используя своё имя пользователя и пароль. (Запрос POST к /rest/usermanagement/1/authentication конечной точке REST). В этом случае вы больше не можете использовать UserDetailsService, вместо этого вам необходимо реализовать и предоставить AuthenticationProvider @Bean. AuthenticationProvider состоит в основном из одного метода, и простая реализация может выглядеть так: 1) По сравнению с методом load () UserDetails, где у вас был доступ только к имени пользователя, теперь у вас есть доступ к полной попытке аутентификации, обычно содержащей имя пользователя и пароль. 2) Вы можете делать всё, что хотите для аутентификации пользователя, например, вызывать REST-сервис. 3) Если аутентификация не удалась, вам нужно выбросить исключение. 4) Если аутентификация прошла успешно, вам необходимо вернуть полностью инициализированный UsernamePasswordAuthenticationToken. Это реализация интерфейса аутентификации, и для него необходимо, чтобы в поле Authenticated было установлено значение true (которое конструктор, использованный выше, установит автоматически). Как это работает в Spring Security (поэтапно): 1) Извлеките комбинацию имени пользователя и пароля из заголовка HTTP Basic Auth в фильтре. Для этого не нужно ничего делать, это произойдет под капотом. 2) Позвоните своему AuthenticationProvider (например, AtlassianCrowdAuthenticationProvider) с этим именем пользователя и паролем, чтобы вы могли самостоятельно выполнить аутентификацию (например, вызов REST). 3) Хеширования паролей не происходит, поскольку вы по сути делегируете стороннему лицу выполнение проверки имени пользователя/пароля. Это в двух словах об аутентификации AuthenticationProvider! Вывод из этого раздела: если вы используете Spring Security и не имеете доступа к паролю пользователя, то реализуйте и предоставьте AuthenticationProvider @Bean . |
7. Что такое OAuth2? |
Краткий ответ: По своей сути OAuth2 - это просто среда авторизации, предоставляющая клиентам доступ к защищенным ресурсам через сервер авторизации. Ничего себе, это предложение не помогает вообще , не так ли? К счастью, есть и длинный ответ: и он находится по этой ссылке. |
8. Что такое авторизация? (нужна для того, чтобы ограничить доступ к некоторым частям приложения) |
В большинстве приложений есть концепция разрешений (или ролей). Представьте себе: клиентов, которые имеют доступ к общедоступному интерфейсу вашего интернет-магазина, и администраторов, у которых есть доступ к отдельной области администрирования. Оба типа пользователей должны входить в систему, но сам факт аутентификации ничего не говорит о том, что им разрешено делать в вашей системе. Следовательно, вам также необходимо проверить разрешения аутентифицированного пользователя (его роль), то есть вам необходимо авторизовать пользователя. - Пользователь: «Позвольте мне сыграть в этот ядерный футбол…». - Ваше веб-приложение: « Ваше разрешение, секундочку, мне нужно проверить… да, господин президент, у вас правильный уровень допуска. Наслаждайтесь». - Пользователь: «Что это за красную кнопку я сейчас нажал…??» (Звуки паники). У клиента не должно быть доступа к колл-центру или админке. Ему разрешено делать покупки только на веб-сайте. Агент центра обработки вызовов не должен иметь доступ к области администрирования. В то время как администратор может получить доступ к интернет-магазину, области call-центра и области администрирования. Проще говоря, вы хотите предоставить разным пользователям разный доступ в зависимости от их полномочий (Authorities) или ролей (Roles). |
9. Разница между Authorities и Roles? Методы hasRole и has Authority? |
Полномочия — это просто строка, может быть какой угодно, например: пользователь, ADMIN, ROLE_ADMIN или 53cr37_r0l3. Роль — это авторитет с ROLE_префиксом. Итак, роль ADMIN — это то же самое, что полномочие ROLE_ADMIN. hasAuthority('ROLE_ADMIN') то же, что и hasRole('ADMIN') потому, что ROLE_префикс добавляется автоматически. hasRole — это просто авторитет со специальным ROLE_префиксом. hasRole ожидает, что у нас будет префикс ROLE_, тогда как hasAuthority не ожидает и точно вычисляет, то, что передаётся. Различие между ролями и полномочиями носит чисто концептуальный характер и часто сбивает с толку людей, плохо знакомых с Spring Security. Собственно концептуальное отличие заключается в том, что мы можем использовать роли как контейнер для полномочий. Для юзера разрешить полномочие чтения. А для роли админа дать полномочия на чтение, удаление, запись данных и их изменение. Это можно сделать с помощью UserDetailsService. А собрать все роли с полномочиями и сделать их доступными можно с помощью метода getAuthorities(). Полномочия — это (ярлык) способность обеспечивать соблюдение правил или отдавать приказы, в то время как роль — это персонаж или роль, которую играет исполнитель или актер. (edited) Изучаем здесь! |
10. Что такое фильтр сервлетов? |
С ервлетный фильтр занимается предварительной обработкой HTTP-запросов (контролируют и по необходимости изменяют), прежде чем те попадают в сервлет, и/или последующей обработкой HTTP-ответов, исходящих из сервлета. Фильтр сервлетов может перехватывать запросы как для сервлетов, так и для файлов JSP, HTML или другого статического содержимого. Сервлетные фильтры могут: - перехватывать инициацию сервлета прежде, чем сервлет будет инициирован; - определить содержание запроса прежде, чем сервлет будет инициирован; - модифицировать заголовки и данные запроса, в которые упаковывается поступающий запрос; - модифицировать заголовки и данные ответа, в которые упаковывается получаемый ответ; - перехватывать инициацию сервлета после обращения к сервлету. Сервлетный фильтр может быть сконфигурирован так, что он будет работать с одним сервлетом или группой сервлетов. Одно важное различие часто упускается из виду: при прослушивании для запроса, фильтры работают с диспетчерами контейнеров сервлетов. Для вызова одного прослушивателя могут быть несколько фильтров/вызовы сервлета. |
11. Как создать свой фильтр сервлета? (2 способа) |
И спользуем аннотацию @WebFilter. Имплементируем Filter и переопределяем 3 метода жизненного цикла фильтра. Init, doFilter, destroy. Или использовать элемент |
12. Жизненный цикл фильтра сервлетов? Интерфейс javax.servlet.Filter |
Фильтр запускается перед визуализацией (view), но после отображения ответа контроллера (Controller). Основой для формирования фильтров служит интерфейс javax.servlet.Filter, он реализует 3 метода: 1) voidinit (FilterConfig config) throws ServletException – Сервер вызывает метод init один раз прежде, чем фильтр начинает работать, и определяет конфигурационные параметры фильтра. Бросает ServletException. 2) voiddoFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException – Метод doFilter выполняет работу фильтра и будет вызван столько раз, сколько запросов будет сделано к данному фильтру. Бросает 2 исключения, IOException или ServletException. 3) voiddestroy() – После того, как фильтр заканчивает свою работу, вызывается метод destroy. |
13. Подробнее о работе метода doFilter? |
Когда HTTP-запрос поступает в ваше веб-приложение, которое перехватывает фильтр, фильтр может проверять URI запроса, параметры запроса и заголовки запроса и на основе этого решать, хочет ли он заблокировать или перенаправить запрос на целевой сервлет, JSP и т.п. Типичная реализация этого метода будет следовать следующему шаблону: 1. Изучить запрос; 2. При желании обернуть объект запроса пользовательской реализацией для фильтрации ввода; 3. При желании обернуть объект ответа пользовательской реализацией для выходной фильтрации; 4. a) Либо вызывать следующий объект в цепочке с помощью объекта FilterChain ( chain.doFilter()); 4. b) Либо не передавать пару запрос/ответ следующему объекту в цепочке фильтров, чтобы заблокировать запрос; 5. Отправка заголовка в ответ, после вызова следующего объекта в цепочке фильтров. Обратите внимание, как doFilter() проверяет параметр запроса myParam, чтобы убедиться, что он равен строке «blockTheRequest». В противном случае запрос направляется к цели запроса путем вызова filterChain.doFilter()метода. Если этот метод не вызывается, запрос не пересылается, а просто блокируется. |
14. Подробнее о работе метода destroy? |
Вызывается веб-контейнером, чтобы указать фильтру, что он выводится из эксплуатации. Метод вызывается только после завершения всех потоков в методе doFilter или по истечении периода ожидания. После того, как веб-контейнер вызовет этот метод, он больше не будет вызывать doFilter для этого экземпляра фильтра. Этот метод даёт фильтру возможность очистить любые удерживаемые ресурсы (память, дескрипторы файлов, потоки) и убедиться, что любое постоянное состояние синхронизируется с текущим состоянием фильтра в памяти. |
15. Виды фильтров? |
1) Фильтры аутентификации 2) Фильтры регистрации и аудита 3) Фильтры преобразования изображений 4) Фильтры сжатия данных 5) Фильтры шифрования 6) Фильтры токенизации 7) Фильтры, запускающие события доступа к ресурсам 8) XSL / T фильтры 9) Цепной фильтр Mime-типа |
16. Что такое слушатель сервлета (Listener)? Интерфейс javax.servlet.ServletContextListener |
Слушатель сервлета используется для прослушивания событий в веб-контейнерах, например, при создании сеанса или при размещении атрибута в сеансе. Вы можете отслеживать и реагировать на события в жизненном цикле сервлетов, определяя объекты-слушатели (например HttpSessionListener), методы которых вызываются при возникновении событий жизненного цикла. С помощью слушателей вы можете отслеживать уровень приложения, уровень сеанса, и атрибут изменения жизненного цикла. Самая лучшая статья на эту тему тут! |
17. Принципиальное отличие фильтра сервлета от слушателя (Listener)? |
-Фильтр — это как фильтр воды, в нём будут отфильтрованы входящие (запрос) и исходящие (ответные) значения. - Слушатель похож на прослушивание (триггер) - при необходимости я буду выполнять (передавать в фильтр запросы и ответы). |
18. Как происходит /logout из системы? |
При нажатии кнопки выхода, браузер отправляет запрос на /j_spring_security_logout , он сначала отправляется на org/springframework/security/web/authentication/logout/LogoutFilter , который затем делегирует задачу выхода на реализацию org/springframework/security/web/authentication/logout/LogoutHandler org/springframework/security/web/authentication/logout/SecurityContextLogoutHandler — это реализация LogoutHandler , и у неё есть метод logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) , который будет вызван LogoutFilter. LogoutHandler в первую очередь делает две вещи; - Делает сеанс недействительным, если он настроен на это. - Очищает SecurityContextHolder , где хранятся данные аутентификации. |
19. Интерфейс Principal, что это? @AuthenticationPrincipal? |
П ринципал — это текущий вошедший в систему пользователь. Благодаря нему, вы всегда можете получить Principal объект, получить имя принципала и найти пользователя по имени пользователя. Однако вы извлекаете его через контекст безопасности, который привязан к текущему потоку, и как таковой он также привязан к текущему запросу и его сеансу. SecurityContextHolder.getContext() внутренне получает текущую реализацию SecurityContext через переменную ThreadLocal. Поскольку запрос привязан к одному потоку, это даст вам контекст текущего запроса. Для упрощения можно сказать, что контекст безопасности находится в сеансе и содержит user/principal и roles/authorities. Principal имеет только один собственный метод getName(). Фактически принципалом пользователя может выступать его логин, пароль, или роль и т.д. Смотрим тут! @AuthenticationPrincipal предоставляет элегантное решение, начиная с Spring Security 3.2 вам больше не нужно реализовывать собственный ArgumentResolver. Если у вас есть UserDetails реализация User, вы можете просто сделать это: @RequestMapping("/messages/inbox") public ModelAndView findMessagesForUser(@AuthenticationPrincipal User activeUser) {} Есть и другой способ получения текущего пользователя через контекст секьюрити при помощи метода getPrincipal(), который возвращает объект аутентифицируемого принципала UserDetails. Object object = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); Если используем предопределённый класс User Spring Security, мы можем привести его к типу org.springframework.security.core.userdetails.User. (User) UserDetails userDetails = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal(); |
|