Вы можете использовать это руководство, чтобы понять, что такое Spring Security и как работают ее основные функции, такие как аутентификация, авторизация или защита от распространенных эксплойтов. Кроме того, полный список часто задаваемых вопросов.
( Примечание редактора : При ~ 6500 словах вы, вероятно, не захотите пытаться читать это на мобильном устройстве. Добавьте его в закладки и вернитесь позже.)
Вступление
Рано или поздно каждому нужно добавить безопасность в свой проект, и в экосистеме Spring вы делаете это с помощью библиотеки Spring Security .
Итак, вы идете дальше, добавляете пружинную защиту в свой пружинный ботинок (или обычный Весенний ) проект и внезапно…
… у вас есть автоматически сгенерированные страницы входа в систему.
…вы больше не можете выполнять запросы POST.
…все ваше приложение заблокировано и предлагает вам ввести имя пользователя и пароль.
Пережив последующий психический срыв, вам может быть интересно, как все это работает.
Что такое Spring Security и как она работает?
Короткий ответ :
По своей сути Spring Security – это просто набор фильтров сервлетов, которые помогают вам добавлять аутентификацию и авторизацию в ваше веб-приложение.
Он также хорошо интегрируется с такими фреймворками, как Spring Web MVC (или Spring Boot ), а также со стандартами, такими как OAuth2 или SAML. И он автоматически генерирует страницы входа/выхода и защищает от распространенных эксплойтов, таких как CSRF.
Так вот, это на самом деле не помогает, не так ли?
К счастью, есть также длинный ответ :
Остальная часть этой статьи.
Безопасность веб-приложений: 101
Прежде чем вы станете гуру Spring Security, вам необходимо понять три важных понятия:
Идентификация
Авторизация
Фильтры сервлетов
Родительский совет : Не пропускайте этот раздел, так как он является основой для всего , что делает Spring Security. Кроме того, я сделаю это как можно более интересным.
1. Идентификация
Во-первых, если вы используете обычное (веб-) приложение, вам нужно, чтобы ваши пользователи аутентифицировались . Это означает, что ваше приложение должно проверить, является ли пользователь тем, за кого он себя выдает, обычно это делается с помощью проверки имени пользователя и пароля.
Пользователь : “Я президент Соединенных Штатов. Мое имя пользователя : президент!”
Ваше веб-приложение : “Конечно, конечно, какой у вас пароль тогда, господин Президент?”
Пользователь : “Мой пароль: th3don4ld”.
Ваше веб-приложение : “Правильно. Добро пожаловать, сэр!”
2. Авторизация
В более простых приложениях аутентификации может быть достаточно: Как только пользователь проходит аутентификацию, он может получить доступ ко всем частям приложения.
Но в большинстве приложений существует концепция разрешений (или ролей). Представьте себе: клиенты, у которых есть доступ к общедоступному интерфейсу вашего интернет-магазина, и администраторы, у которых есть доступ к отдельной области администрирования.
Пользователям обоих типов необходимо войти в систему, но сам факт аутентификации ничего не говорит о том, что им разрешено делать в вашей системе. Следовательно, вам также необходимо проверить разрешения аутентифицированного пользователя, т.е. вам необходимо авторизовать пользователя.
Пользователь : “Позвольте мне поиграть с этим ядерным футболом….”
Ваше веб-приложение : “Секунду, мне нужно сначала проверить ваши разрешения ….. да, господин президент, у вас правильный уровень допуска. Наслаждайся”.
Пользователь : “Что это была за красная кнопка опять…??”
3. Фильтры сервлетов
И последнее, но не менее важное: давайте взглянем на фильтры сервлетов. Какое они имеют отношение к аутентификации и авторизации? (Если вы совершенно новичок в Java-сервлетах или фильтрах, я советую вам прочитать старый, но все еще очень актуальный Сервлеты Head First книга.)
Зачем использовать фильтры сервлетов?
Вспомните мою другую статью , где мы выяснили, что в основном любое веб-приложение Spring – это всего один сервлет: старый добрый Диспетчерский сервлет Spring , который перенаправляет входящие HTTP-запросы (например, из браузера) на ваши @Controllers или @RestControllers.
Дело в том, что в этом диспетчерском сервлете нет жесткого кода безопасности, и вы также, скорее всего, не захотите возиться с необработанным заголовком HTTP Basic Auth в ваших @Controllers. Оптимально, чтобы аутентификация и авторизация были выполнены до того, как запрос попадет на ваши @контроллеры.
К счастью, в веб-мире Java есть способ сделать именно это: вы можете поместить фильтры | | перед сервлетами, что означает, что вы можете подумать о написании фильтра безопасности и настроить его в своем Tomcat (контейнер сервлетов/сервер приложений) для фильтрации каждого входящего HTTP-запроса до того, как он попадет в ваш сервлет.
+-------------------------------+ +-----------------------------------+ | Browser | | SecurityFilter (Tomcat) | |-------------------------------| |-----------------------------------| | | | | | https://my.bank/account | -------> | Check if user is authenticated/ | | | | 1. authenticated | | | | 2. authorized | | | | | | | | -- if false: HTTP 401/403 | ---------> +-----------------------------------+ | | | -- if true: continue to servlet | | DispatcherServlet (Tomcat) | | | | | | @RestController/@Controller | | | +-----------------------------------+ +-----------------------------------+ +-------------------------------+
Наивный Фильтр Безопасности
Фильтр безопасности имеет примерно 4 задачи, и наивная и чрезмерно упрощенная реализация может выглядеть следующим образом:
import javax.servlet.*;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SecurityServletFilter extends HttpFilter {
@Override
protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
UsernamePasswordToken token = extractUsernameAndPasswordFrom(request);
if (notAuthenticated(token)) {
// either no or wrong username/password
// unfortunately the HTTP status code is called "unauthorized", instead of "unauthenticated"
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // HTTP 401.
return;
}
if (notAuthorized(token, request)) {
// you are logged in, but don't have the proper rights
response.setStatus(HttpServletResponse.SC_FORBIDDEN); // HTTP 403
return;
}
// allow the HttpRequest to go to Spring's DispatcherServlet
// and @RestControllers/@Controllers.
chain.doFilter(request, response);
}
private UsernamePasswordToken extractUsernameAndPasswordFrom(HttpServletRequest request) {
// Either try and read in a Basic Auth HTTP Header, which comes in the form of user:password
// Or try and find form login request parameters or POST bodies, i.e. "username=me" & "password="myPass"
return checkVariousLoginOptions(request);
}
private boolean notAuthenticated(UsernamePasswordToken token) {
// compare the token with what you have in your database...or in-memory...or in LDAP...
return false;
}
private boolean notAuthorized(UsernamePasswordToken token, HttpServletRequest request) {
// check if currently authenticated user has the permission/role to access this request's /URI
// e.g. /admin needs a ROLE_ADMIN , /callcenter needs ROLE_CALLCENTER, etc.
return false;
}
}
Во-первых, фильтру необходимо извлечь имя пользователя/пароль из запроса. Это может быть через HTTP-заголовок Basic Auth , или поля формы, или файл cookie и т. Д.
Затем фильтру необходимо проверить эту комбинацию имени пользователя/пароля на соответствие чему-либо , например базе данных.
Фильтр должен проверить, после успешной аутентификации, что пользователь авторизован для доступа к запрошенному URI.
Если запрос выдержит все эти проверки, фильтр может разрешить отправку запроса вашему диспетчерскому сервлету, т.е. вашим @контроллерам.
Цепочка фильтров
Проверка реальности: В то время как приведенный выше код работает, компилируется, рано или поздно это приведет к созданию одного фильтра-монстра с тонной кода для различных механизмов аутентификации и авторизации.
В реальном мире, однако, вы бы разделили этот фильтр на несколько фильтров, которые затем связали вместе.
Например, входящий HTTP-запрос будет…
Сначала пройдите через фильтр методов входа в систему…
Затем пройдите через фильтр аутентификации…
Затем пройдите через фильтр авторизации…
Наконец, нажмите на свой сервлет.
Эта концепция называется Цепочка фильтров , и последний вызов метода в вашем фильтре выше фактически делегирует эту самую цепочку:
chain.doFilter(request, response);
С помощью такого фильтра (цепочки) вы можете в основном решать все проблемы с аутентификацией или авторизацией, возникающие в вашем приложении, без необходимости изменять фактическую реализацию приложения (подумайте: ваши @RestControllers/@Контроллеры).
Вооружившись этими знаниями, давайте выясним, как Spring Security использует эту магию фильтра.
Цепочка фильтров и Конфигурация безопасности DSL
Мы начнем рассматривать Spring Security немного нетрадиционно, двигаясь в обратном направлении от предыдущей главы, начиная с цепочки фильтров Spring Security.
Цепочка фильтров Spring по умолчанию для обеспечения безопасности
Давайте предположим, что вы правильно настроили Spring Security, а затем загрузили свое веб-приложение. Вы увидите следующее сообщение в журнале:
2020-02-25 10:24:27.875 INFO 11116 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@46320c9a, org.springframework.security.web.context.SecurityContextPersistenceFilter@4d98e41b, org.springframework.security.web.header.HeaderWriterFilter@52bd9a27, org.springframework.security.web.csrf.CsrfFilter@51c65a43, org.springframework.security.web.authentication.logout.LogoutFilter@124d26ba, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@61e86192, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@10980560, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@32256e68, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@52d0f583, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5696c927, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5f025000, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5e7abaf7, org.springframework.security.web.session.SessionManagementFilter@681c0ae6, org.springframework.security.web.access.ExceptionTranslationFilter@15639d09, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4f7be6c8]|
Если вы развернете эту одну строку в список, похоже, что Spring Security не просто устанавливает один фильтр, вместо этого он устанавливает целую цепочку фильтров, состоящую из 15 (!) различных фильтров.
Таким образом, когда поступает HTTP-запрос, он будет проходить через все эти 15 фильтров, прежде чем ваш запрос, наконец, попадет в ваши @RestControllers. Порядок тоже важен, начиная с верхней части этого списка и спускаясь вниз.
+----------------------------------+ +----------------------------------------+ +---------------------------------------+ | Browser HTTP Request |---------> | SecurityContextPersistenceFilter | -------> | HeaderWriterFilter | -----> +----------------------------------+ +----------------------------------------+ +---------------------------------------+ +----------------------------------+ +----------------------------------------+ +---------------------------------------+ | CsrfFilter |---------> | LogoutFilter | -------> | UsernamePasswordAuthenticationFilter | -----> +----------------------------------+ +----------------------------------------+ +---------------------------------------+ +----------------------------------+ +----------------------------------------+ +--------------------------------------+ | DefaultLoginPageGeneratingFilter |---------> | DefaultLogoutPageGeneratingFilter | -------> | BasicAuthenticationFilter | -----> +----------------------------------+ +----------------------------------------+ +--------------------------------------+ +----------------------------------+ +----------------------------------------+ +--------------------------------------+ | RequestCacheAwareFilter |---------> | SecurityContextHolderAwareRequestFilter| -------> | AnonymousAuthenticationFilter | -----> +----------------------------------+ +----------------------------------------+ +--------------------------------------+ +----------------------------------+ +----------------------------------------+ +--------------------------------------+ | SessionManagementFilter |---------> | ExceptionTranslationFilter | -------> | FilterSecurityInterceptor | -----> +----------------------------------+ +----------------------------------------+ +--------------------------------------+ +----------------------------------+ | your @RestController/@Controller | +----------------------------------+
Анализ цепочки фильтров Spring
Было бы слишком далеко заходить, чтобы подробно рассмотреть каждый фильтр этой цепочки, но вот объяснения для некоторых из этих фильтров. Не стесняйтесь просматривать исходный код Spring Security , чтобы понять другие фильтры.
BasicAuthenticationFilter : Пытается найти базовый HTTP-заголовок аутентификации в запросе и, если найден, пытается аутентифицировать пользователя с помощью имени пользователя и пароля заголовка.
UsernamePasswordAuthenticationFilter : Пытается найти параметр запроса имени пользователя/пароля/текст СООБЩЕНИЯ и, если найден, пытается аутентифицировать пользователя с помощью этих значений.
DefaultLoginPageGeneratingФильтр по умолчанию : Создает для вас страницу входа в систему, если вы явно не отключите эту функцию. ЭТОТ фильтр является причиной того, что при включении Spring Security вы получаете страницу входа по умолчанию.
Фильтр для создания страницы выхода из системы по умолчанию : Создает для вас страницу выхода из системы, если вы явно не отключили эту функцию.
Фильтрбезопасностиинтерцептор : Делает ваше разрешение.
Таким образом, с помощью этих нескольких фильтров Spring Security предоставляет вам страницу входа/выхода, а также возможность входа с помощью базовой авторизации или формы входа, а также пару дополнительных функций, таких как CsrfFilter, которые мы рассмотрим позже.
Перерыв на перерыв : Эти фильтры, по большей части, являются пружинной защитой. Ни больше, ни меньше. Они делают всю работу. Что вам остается, так это настроить как они выполняют свою работу, т.е. какие URL-адреса защищать, какие игнорировать и какие таблицы базы данных использовать для аутентификации.
Следовательно, далее нам нужно взглянуть на то, как настроить Spring Security.
Как настроить Spring Security: WebSecurityConfigurerAdapter
В последних версиях Spring Security и/или Spring Boot можно настроить Spring Security с помощью класса, который:
Снабжен пометкой @EnableWebSecurity.
Расширяет WebSecurityConfigurer, который в основном предлагает вам DSL/методы конфигурации. С помощью этих методов вы можете указать, какие URI в вашем приложении следует защищать или какие средства защиты от эксплойтов следует включать/отключать.
Вот как выглядит типичный адаптер WebSecurityConfigurerAdapter:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.httpBasic();
}
}
Обычная конфигурация Spring @ с аннотацией @EnableWebSecurity, расширяющейся от WebSecurityConfigurerAdapter.
Переопределяя метод настройки адаптера (HttpSecurity), вы получаете приятный маленький DSL, с помощью которого вы можете настроить свою цепочку фильтров.
Все запросы направляются в
/и/домойразрешены (разрешены) – пользователь не должен проходить аутентификацию. Вы используете antmatchers , что означает, что вы могли бы также использовать подстановочные знаки (*, \*\*, ?) в строке.Для любого другого запроса требуется аутентификация пользователя сначала , т.е. пользователю необходимо войти в систему.
Вы разрешаете вход в форму (имя пользователя/пароль в форме) с пользовательской страницей входа (
/вход, т.Е. не автоматически сгенерированный Spring Security). Любой желающий должен иметь возможность получить доступ к странице входа в систему без необходимости сначала входить в систему (разрешено; в противном случае у нас был бы улов-22!).То же самое относится и к странице выхода из системы
Кроме того, вы также разрешаете базовую аутентификацию, т.Е. отправку заголовка HTTP Basic Auth для аутентификации.
Как использовать Spring Security для настройки DSL
Требуется некоторое время, чтобы привыкнуть к этому DSL, но вы найдете больше примеров в разделе часто задаваемых вопросов: Муравьеды: Общие примеры .
Что сейчас важно, так это то, что ЭТОТ метод настройки – это то, где вы указываете:
Какие URL-адреса следует защищать (аутентифицированные()), а какие разрешены (PermitAll()).
Какие методы аутентификации разрешены (форма входа(), httpBasic()) и как они настроены.
Короче говоря: полная конфигурация безопасности вашего приложения.
Примечание : Вам не нужно было бы сразу переопределять метод настройки адаптера, потому что он поставляется с довольно разумной реализацией – по умолчанию. Вот как это выглядит:
public abstract class WebSecurityConfigurerAdapter implements
WebSecurityConfigurer {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.httpBasic();
}
}
Чтобы получить доступ к любому URI (
любому запросу()) в вашем приложении, вам необходимо пройти аутентификацию (аутентифицированный()).Форма входа в систему (
форма входа в систему()) с настройками по умолчанию включена.Как и базовая аутентификация HTTP (
http Basic()).
Эта конфигурация по умолчанию является причиной того, что ваше приложение заблокировано, как только вы добавите в него Spring Security. Просто, не так ли?
Резюме: Конфигурация DSL Websecurityconfigureradapter
Мы узнали, что Spring Security состоит из нескольких фильтров, которые вы настраиваете с помощью класса WebSecurityConfigurerAdapter @Configuration.
Но здесь не хватает одной важной детали. Давайте возьмем, к примеру, базовый фильтр Spring. Он может извлечь имя пользователя/пароль из заголовка HTTP Basic Auth, но что он аутентифицирует эти полномочия против?
Это, естественно, приводит нас к вопросу о том, как аутентификация работает с Spring Security.
Аутентификация с помощью Spring Security
Когда дело доходит до аутентификации и безопасности Spring, у вас есть примерно три сценария:
Значение по умолчанию : Вы можете получить доступ к (зашифрованному) паролю пользователя, потому что у вас есть его данные (имя пользователя, пароль), сохраненные, например, в таблице базы данных.
Менее распространенный : Вы не можете получить доступ к (зашифрованному) паролю пользователя. Это тот случай, если ваши пользователи и пароли хранятся где-то в другом месте, например, в стороннем продукте управления идентификацией, предлагающем услуги REST для аутентификации. Подумайте: Атласская толпа .
Также популярно : Вы хотите использовать OAuth2 или “Войти в систему с помощью Google/Twitter/и т. Д.”. (OpenID), вероятно, в сочетании с JWT. Тогда ни одно из следующих действий не применимо, и вам следует сразу перейти к главе OAuth2 .
Примечание : В зависимости от вашего сценария вам необходимо указать разные @Beans, чтобы заставить Spring Security работать, в противном случае вы получите довольно запутанные исключения (например, исключение NullPointerException, если вы забыли указать кодер пароля). Имейте это в виду.
Давайте взглянем на два главных сценария.
1. Служба пользовательских данных: Имея доступ к паролю пользователя
Представьте, что у вас есть таблица базы данных, в которой вы храните своих пользователей. В нем есть пара столбцов, но самое главное, что в нем есть столбец имени пользователя и пароля, где вы храните зашифрованный (!) пароль пользователя.
create table users (id int auto_increment primary key, username varchar(255), password varchar(255));
В этом случае Spring Security требует, чтобы вы определили два компонента для запуска и запуска аутентификации.
Служба пользовательских данных.
Кодировщик паролей.
Указать службу пользовательских данных так же просто, как это:
@Bean
public UserDetailsService userDetailsService() {
return new MyDatabaseUserDetailsService();
}
- Моя база данных UserDetailsService реализует UserDetailsService, очень простой интерфейс, который состоит из одного метода, возвращающего объект UserDetails:
public class MyDatabaseUserDetailsService implements UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 1. Load the user from the users table by username. If not found, throw UsernameNotFoundException.
// 2. Convert/wrap the user to a UserDetails object and return it.
return someUserDetails;
}
}
public interface UserDetails extends Serializable {
String getUsername();
String getPassword();
// <3> more methods:
// isAccountNonExpired,isAccountNonLocked,
// isCredentialsNonExpired,isEnabled
}
Служба пользовательских данных загружает данные пользователя через имя пользователя. Обратите внимание, что метод принимает только один параметр: имя пользователя (не пароль).
В интерфейсе пользовательских данных есть методы для получения (зашифрованного!) пароль и один, чтобы получить имя пользователя.
Сведения о пользователе содержат еще больше методов, например, активна или заблокирована учетная запись, истек срок действия учетных данных или какие разрешения у пользователя, но мы не будем их здесь описывать.
Таким образом, вы можете либо реализовать эти интерфейсы самостоятельно, как мы сделали выше, либо использовать существующие, которые предоставляет Spring Security.
Готовые Реализации
Просто краткое примечание: Вы всегда можете самостоятельно реализовать интерфейсы UserDetailsService и Сведений о пользователе.
Но вы также найдете готовые реализации Spring Security, которые вы можете использовать/настраивать/расширять/переопределять вместо этого.
JdbcUserDetailsManager , который представляет собой службу пользовательских данных на основе JDBC(базы данных). Вы можете настроить его так, чтобы он соответствовал вашей пользовательской структуре таблицы/столбца.
InMemoryUserDetailsManager , который хранит все данные пользователя в памяти и отлично подходит для тестирования.
org.springframework.безопасность.ядро.пользовательские данные. Пользователь , который является разумной реализацией пользовательских данных по умолчанию, которую вы могли бы использовать. Это означало бы потенциальное сопоставление/копирование между вашими сущностями/таблицами базы данных и этим пользовательским классом. В качестве альтернативы вы можете просто заставить свои сущности реализовывать интерфейс UserDetails.
Рабочий процесс с полной информацией о пользователе: Базовая аутентификация HTTP
Теперь вспомните свою базовую аутентификацию HTTP, это означает, что вы защищаете свое приложение с помощью Spring Security и базовой аутентификации. Это то, что происходит, когда вы указываете службу пользовательских данных и пытаетесь войти в систему:
Извлеките комбинацию имени пользователя и пароля из заголовка HTTP Basic Auth в фильтре. Вам не нужно ничего для этого делать, это произойдет под капотом.
Позвоните своему Моя база данных Userdetailsсервис для загрузки соответствующего пользователя из базы данных, завернутый в объект UserDetails, который предоставляет зашифрованный пароль пользователя.
Возьмите извлеченный пароль из заголовка HTTP Basic Auth, зашифруйте его автоматически и сравните его с зашифрованным паролем из вашего объекта UserDetails. Если оба совпадают, пользователь успешно прошел аутентификацию.
Вот и все, что в этом есть. Но подождите, как Spring Security шифрует пароль от клиента (шаг 3)? С помощью какого алгоритма?
Кодировщик паролей
Spring Security не может волшебным образом угадать предпочитаемый вами алгоритм шифрования пароля. Вот почему вам нужно указать другой @компонент, a Кодер пароля . Если вы хотите, скажем, использовать шифрование BCRYPT (по умолчанию Spring Security) для всех ваших паролей , вы должны указать этот @компонент в своей SecurityConfig.
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
Что делать, если у вас есть несколько алгоритмов шифрования паролей, потому что у вас есть несколько устаревших пользователей, чьи пароли хранились с MD5 (не делайте этого), и более новые с Bcrypt или даже третьим алгоритмом, таким как SHA-256? Тогда вы бы использовали следующий кодировщик:
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
Как работает этот делегирующий кодировщик? Он будет просматривать зашифрованный пароль пользователя (например, из таблицы вашей базы данных), который теперь должен начинаться с {префикс} . Этот префикс – ваш метод шифрования! Тогда ваша таблица базы данных будет выглядеть следующим образом:
| имя пользователя | пароль | |
| john@doe.com | {bcrypt}$2y$12$6t86Rpr3llMANhCUt26oUen2WhvXr/a89xo9zjion8w7gwgz/za 0C | |
| my@user.com | { sha256}5ffa39f5757a0dad5dfada519d02c6b71b61ab1df51b4ed1f3beed6abe0ff5f6 |
Весенняя безопасность будет:
Прочитайте эти пароли и удалите префикс ( {bcrypt} или {sha256} ).
В зависимости от значения префикса используйте правильный кодер пароля (т.Е. кодер BCRYPT или кодер sha256).
Зашифруйте входящий незашифрованный пароль с помощью этого кодера паролей и сравните его с сохраненным.
Это все, что нужно для кодирования паролей.
Резюме: Имея доступ к паролю пользователя
Вывод для этого раздела таков: если вы используете Spring Security и имеете доступ к паролю пользователя, то:
Укажите службу пользовательских данных. Либо пользовательская реализация, либо используйте и настройте ту, которую предлагает Spring Security.
Укажите кодер пароля.
Это аутентификация Spring Security в двух словах.
2. Поставщик аутентификации: Отсутствие доступа к паролю пользователя
Теперь представьте, что вы используете Atlassian Crowd для централизованного управления идентификацией. Это означает, что все ваши пользователи и пароли для всех ваших приложений хранятся в Atlassian Crowd, а не в таблице вашей базы данных.
Это имеет два следствия:
У вас больше нет паролей пользователей в вашем приложении, так как вы не можете попросить Crowd просто предоставить вам эти пароли.
Однако у вас есть REST API, с помощью которого вы можете войти в систему, используя свое имя пользователя и пароль. (Запрос POST на конечную точку
/rest/управление пользователями/1/аутентификацияREST).
Если это так, вы больше не можете использовать службу пользовательских данных, вместо этого вам необходимо реализовать и предоставить AuthenticationProvider @Bean.
@Bean
public AuthenticationProvider authenticationProvider() {
return new AtlassianCrowdAuthenticationProvider();
}
Поставщик аутентификации состоит в основном из одного метода, и наивная реализация может выглядеть следующим образом:
public class AtlassianCrowdAuthenticationProvider implements AuthenticationProvider {
Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String username = authentication.getPrincipal().toString();
String password = authentication.getCredentials().toString();
User user = callAtlassianCrowdRestService(username, password);
if (user == null) {
throw new AuthenticationException("could not login");
}
return new UserNamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), user.getAuthorities());
}
// other method ignored
}
По сравнению с методом загрузки сведений о пользователе(), когда у вас был доступ только к имени пользователя, теперь у вас есть доступ к полной попытке аутентификации, обычно содержащей имя пользователя и пароль.
Вы можете делать все, что хотите, для аутентификации пользователя, например, вызывать службу REST.
Если аутентификация не удалась, вам необходимо создать исключение.
Если аутентификация прошла успешно, вам необходимо вернуть полностью инициализированный пароль UsernamePasswordAuthenticationToken. Это реализация интерфейса аутентификации, и для поля аутентификация должно быть установлено значение true (которое автоматически установит конструктор, используемый выше). Мы рассмотрим авторитеты в следующей главе.
Полный рабочий процесс Поставщика аутентификации: Базовая аутентификация HTTP
Теперь вспомните свою базовую аутентификацию HTTP, это означает, что вы защищаете свое приложение с помощью Spring Security и базовой аутентификации. Вот что происходит, когда вы указываете поставщика аутентификации и пытаетесь войти в систему:
Извлеките комбинацию имени пользователя и пароля из заголовка HTTP Basic Auth в фильтре. Вам не нужно ничего для этого делать, это произойдет под капотом.
Позвоните своему Поставщику аутентификации (например, поставщику аутентификации Atlassian Crowd) с этим именем пользователя и паролем, чтобы вы могли самостоятельно выполнить аутентификацию (например, вызов REST).
Там нет шифрования пароля или чего-то подобного, так как вы, по сути, делегируете третьей стороне фактическую проверку имени пользователя/пароля. Это аутентификация поставщика аутентификации в двух словах!
Краткое описание: Поставщик аутентификации
Вывод для этого раздела таков: если вы используете Spring Security и не имеете доступа к паролю пользователя, то внедрите и предоставьте AuthenticationProvider @Bean .
Авторизация с помощью Spring Security
До сих пор мы говорили только об аутентификации, например, проверке имени пользователя и пароля.
Давайте теперь посмотрим на разрешения, а точнее роли и власти весной говорят о безопасности.
Что такое Авторизация?
Возьмем ваш типичный интернет-магазин электронной коммерции. Скорее всего, он состоит из следующих частей:
Сам интернет-магазин. Давайте предположим, что это URL-адрес
www.youramazinshop.com.Может быть область для агентов колл-центра, где они могут войти в систему и посмотреть, что недавно купил клиент или где находится его посылка. Его URL-адрес будет
www.youramazinshop.com/callcenter.Отдельная область администрирования, где администраторы могут входить в систему и управлять агентами колл-центра или другими техническими аспектами (такими как темы, производительность и т.д.) интернет-магазина. Его URL-адрес будет
www.youramazinshop.com/admin.
Это имеет следующие последствия, поскольку простой аутентификации пользователей уже недостаточно:
Очевидно, что клиент не должен иметь доступа к центру обработки вызовов или административной области. Ему разрешено делать покупки только на веб-сайте.
Агент колл-центра не должен иметь доступа к административной области.
Принимая во внимание, что администратор может получить доступ к интернет-магазину, зоне колл-центра и административной области.
Проще говоря, вы хотите разрешить разный доступ для разных пользователей, в зависимости от их полномочий или ролей .
Что такое Авторитеты? Что такое Роли?
Простой:
Полномочия (в простейшей форме) – это просто строка, она может быть любой, например: пользователь, АДМИНИСТРАТОР, РОЛЬ_АДМИН или 53cr37_r0 l3.
Роль – это полномочия с префиксом
ROLE_. Таким образом, роль, называемаяАДМИНИСТРАТОР, совпадает с полномочиями, называемымиROLE_ADMIN.
Различие между ролями и полномочиями носит чисто концептуальный характер и часто сбивает с толку людей, не знакомых с Spring Security.
Почему существует различие между ролями и полномочиями?
Честно говоря, я прочитал документацию по безопасности Spring, а также пару связанных потоков StackOverflow по этому самому вопросу и я не могу дать вам окончательного, хорошего ответ.
Что такое Предоставленные Полномочия? Что такое Simplegrantedauthority?
Конечно, Spring Security не позволяет вам обходиться без просто использования строк. Существует класс Java, представляющий вашу строку полномочий, популярным из которых является SimpleGrantedAuthority.
public final class SimpleGrantedAuthority implements GrantedAuthority {
private final String role;
@Override
public String getAuthority() {
return role;
}
}
(Примечание: Существуют и другие классы полномочий, которые позволяют хранить дополнительные объекты (например, принципал) рядом с вашей строкой, я не буду их здесь описывать. На данный момент мы будем использовать только SimpleGrantedAuthority.)
1. Служба пользовательских данных: Где хранить и получать данные?
Предполагая, что вы храните пользователей в своем собственном приложении (подумайте: UserDetailsService), у вас будет таблица пользователей.
Теперь вы просто добавите в него колонку под названием “органы власти”. Для этой статьи я выбрал здесь простой строковый столбец, хотя он может содержать несколько значений, разделенных запятыми. В качестве альтернативы я мог бы также иметь совершенно отдельную таблицу ПОЛНОМОЧИЙ, но для объема этой статьи это подойдет.
Примечание: Возвращаясь к section_title : Вы сохраняете полномочия , т.е. строки, в базе данных. Так получилось, что эти полномочия начинаются с префикса ROLE_, поэтому с точки зрения безопасности Spring эти полномочия также являются ролями.
| имя пользователя | пароль | власти | |
| john@doe.com | {bcrypt}… | РОЛЬ_АДМИН | |
| my@callcenter.com | {sha256}… | ЦЕНТР РОЛЕВЫХ ВЫЗОВОВ |
Единственное, что осталось сделать, это настроить ваш сервис пользовательских данных для чтения в этой колонке полномочий.
public class MyDatabaseUserDetailsService implements UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findByUsername(username);
List grantedAuthorities = user.getAuthorities().map(authority -> new SimpleGrantedAuthority(authority)).collect(Collectors.toList());
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
}
Вы просто сопоставляете все, что находится внутри столбца вашей базы данных, со списком простых предоставленных полномочий. Сделано.
Опять же, здесь мы используем базовую реализацию пользовательских данных Spring Security. Вы также можете использовать свой собственный класс, реализующий здесь пользовательские данные, и, возможно, тогда вам даже не придется сопоставлять.
2. AuthenticationManager: Где хранить и получать полномочия?
Когда пользователи приходят из стороннего приложения, такого как Atlassian Cloud, вам нужно будет выяснить, какую концепцию они используют для поддержки органов власти. У Atlassian Crowd были понятия “роли”, но они отказались от них в пользу “групп”.
Таким образом, в зависимости от фактического продукта, который вы используете, вам необходимо сопоставить это с центром безопасности Spring в вашем поставщике аутентификации.
public class AtlassianCrowdAuthenticationProvider implements AuthenticationProvider {
Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String username = authentication.getPrincipal().toString();
String password = authentication.getCredentials().toString();
atlassian.crowd.User user = callAtlassianCrowdRestService(username, password);
if (user == null) {
throw new AuthenticationException("could not login");
}
return new UserNamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), mapToAuthorities(user.getGroups()));
}
// other method ignored
}
Примечание: Это не актуально Атласский код толпы, но служит своей цели. Вы проходите аутентификацию в службе REST и получаете обратно объект пользователя JSON, который затем преобразуется в файл atlassian.crowd. Объект пользователя.
Этот пользователь может быть членом одной или нескольких групп, которые здесь считаются просто строками. Затем вы можете просто сопоставить эти группы с Spring “SimpleGrantedAuthority”.
Пересмотр адаптера конфигурации веб-безопасности для органов власти
До сих пор мы много говорили о хранении и получении полномочий для аутентифицированных пользователей в Spring Security. Но как вы защищаете URL-адреса с разными полномочиями с помощью DSL Spring Security? Простой:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin").hasAuthority("ROLE_ADMIN")
.antMatchers("/callcenter").hasAnyAuthority("ROLE_ADMIN", "ROLE_CALLCENTER")
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
}
Для доступа к
/области администраторавам (т.е. пользователю) необходимо пройти аутентификацию И иметь полномочия (простая строка) ROLE_ADMIN.Для доступа в
/центр обработки вызововвам необходимо пройти аутентификацию И иметь либо полномочия ROLE_ADMIN , ЛИБО ЦЕНТР РОЛЕВЫХ ВЫЗОВОВ.Для любого другого запроса вам не нужна определенная роль, но все равно необходимо пройти проверку подлинности.
Обратите внимание, что приведенный выше код (1,2) является эквивалентным к следующему:
http
.authorizeRequests()
.antMatchers("/admin").hasRole("ADMIN")
.antMatchers("/callcenter").hasAnyRole("ADMIN", "CALLCENTER")
Вместо того, чтобы называть “hasAuthority”, теперь вы называете “hasRole”. Примечание : Spring Security будет искать полномочия с именем
ROLE_ADMINдля аутентифицированного пользователя.Вместо того, чтобы называть “hasAnyAuthority”, вы теперь называете “Hasanyrole”. Примечание : Spring Security будет искать полномочия с именем
ROLE_ADMINилиЦЕНТР РОЛЕВЫХ ВЫЗОВОВна аутентифицированном пользователе.
имеет доступ и СпЕЛ
И последнее, но не менее важное: наиболее эффективный способ настройки авторизации – это метод доступ . Это позволяет вам указывать практически любые допустимые выражения правописания.
http
.authorizeRequests()
.antMatchers("/admin").access("hasRole('admin') and hasIpAddress('192.168.1.0/24') and @myCustomBean.checkAccess(authentication,request)")
- Вы проверяете, что у пользователя есть ROLE_ADMIN, с определенным IP-адресом, а также пользовательской проверкой компонента.
Чтобы получить полный обзор того, что возможно с помощью управления доступом на основе выражений Spring, ознакомьтесь с официальной документацией .
Общие средства защиты от эксплойтов
Существует множество распространенных атак, от которых Spring Security помогает вам защититься. Он начинается с временных атак (т.Е. Spring Security всегда будет шифровать предоставленный пароль при входе в систему, даже если пользователь не существует) и заканчивается защитой от атак контроля кэша, прослушивания контента, взлома кликов, межсайтового скриптинга и многого другого.
В рамках данного руководства невозможно подробно описать каждую из этих атак. Следовательно, мы рассмотрим только одну защиту, которая больше всего сбивает с толку новичков Spring Security: подделка межсайтовых запросов.
Межсайтовый запрос-Подделка: CSRF
Если вы совершенно новичок в CSRF, возможно, вам захочется посмотреть это видео на YouTube , чтобы войти в курс дела. Однако быстрый вывод заключается в том, что по умолчанию Spring Security защищает любой входящий запрос POST (или PUT/DELETE/PATCH) с помощью действительного токена CSRF.
Что это значит?
CSRF и HTML-рендеринг на стороне сервера
Представьте себе форму банковского перевода или любую форму (например, форму входа в систему), если на то пошло, которая отображается вашими контроллерами @ с помощью технологии создания шаблонов, такой как Thymeleaf или Freemarker.
С включенной защитой Spring вы больше не сможете отправлять эту форму . Потому что CSRFFilter Spring Security ищет дополнительный скрытый параметр в любом СООБЩЕНИИ Запрос (ВСТАВИТЬ/УДАЛИТЬ): так называемый токен CSRF.
Он генерирует такой токен по умолчанию для каждого сеанса HTTP и сохраняет его там. И вам нужно обязательно ввести его в любую из ваших HTML-форм.
Токены CSRF и вилочковый лист
Поскольку Thymeleaf имеет хорошую интеграцию с Spring Security (при использовании вместе с Spring Boot), вы можете просто добавить следующий фрагмент в любую форму, и вы автоматически введете токен из сеанса в свою форму. Еще лучше, если вы используете “th:действие” для своей формы, Thymeleaf автоматически введет это скрытое поле для вас, без необходимости делать это вручную.
Здесь мы добавляем параметр CSRF вручную.
Здесь мы используем поддержку формы Thymeleaf.
Примечание: Для получения дополнительной информации о поддержке CSRF Thymeleaf см. официальную документацию .
CSRF и другие Библиотеки шаблонов
Я не могу охватить все библиотеки шаблонов в этом разделе, но в качестве последнего средства вы всегда можете ввести токен CSRF в любой из ваших методов @Controller и просто добавить его в модель, чтобы отобразить его в представлении или получить к нему прямой доступ как атрибут запроса HttpServletRequest.
@Controller
public class MyController {
@GetMaping("/login")
public String login(Model model, CsrfToken token) {
// the token will be injected automatically
return "/templates/login";
}
}
CSRF и реагировать или угловой
Для приложения на Javascript все немного иначе, например, для одностраничного приложения Reactor Angular. Вот что вам нужно сделать:
Настройте Spring Security на использование репозитория CsrfToken файлов cookie , который поместит токен CSRF в файл cookie “XSRF-ТОКЕН” (и отправит его в браузер).
Сделайте так, чтобы ваше приложение Javascript принимало это значение файла cookie и отправляло его в виде “X-XSRF-ТОКЕНА” заголовок с каждым запросом на ПУБЛИКАЦИЮ (/РАЗМЕЩЕНИЕ/ИСПРАВЛЕНИЕ/УДАЛЕНИЕ).
Для полного примера копирования и вставки React взгляните на этот замечательный пост в блоге: https://developer.okta.com/blog/2018/07/19/simple-crud-react-and-spring-boot .
Отключение CSRF
Если вы предоставляете только API REST без состояния, где защита CSRF не имеет никакого смысла, вы бы полностью отключили защиту CSRF. Вот как бы вы это сделали:
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
}
}
OAuth2
Бадум-тиш! Этот раздел – всего лишь тизер для следующей статьи: Spring Security & OAuth2. Почему?
Потому что интеграция Spring Security с OAuth2 на самом деле является сложной темой, и ее достаточно еще для 7000-10 000 слов, которые не вписываются в рамки этой статьи.
Оставайтесь с нами.
Весенние интеграции
Весенняя безопасность и Весенняя основа
В большей части этой статьи вы указали конфигурации безопасности только на веб-уровне вашего приложения. Вы защитили определенные URL-адреса с помощью antMatcher или регулярных выражений с помощью DSL Websecurityconfigureradapter. Это совершенно правильный и стандартный подход к обеспечению безопасности.
В дополнение к защите вашего веб-уровня, существует также идея “глубокой защиты”. Это означает, что в дополнение к защите URL-адресов вы можете захотеть защитить саму свою бизнес-логику. Подумайте: ваши @Контроллеры, @Компоненты, @Сервисы или даже @Репозитории. Короче говоря, ваши весенние бобы.
Безопасность метода
Этот подход называется безопасность метода и работает с помощью аннотаций, которые вы можете в основном разместить в любом общедоступном методе ваших компонентов Spring. Вам также необходимо явно включить безопасность метода, поместив аннотацию @enableglobalmethod в вашу конфигурацию ApplicationContextConfiguration.
@Configuration
@EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
public class YourSecurityConfig extends WebSecurityConfigurerAdapter{
}
Свойство prepostenabled обеспечивает поддержку
@предварительной авторизации Springи@PostAuthorizeаннотации. Поддержка означает, что Spring будет игнорировать эту аннотацию, если вы не установите флаг в значение true.Свойство “Защищено включено” позволяет поддерживать аннотацию
@Защищено. Поддержка означает, что Spring будет игнорировать эту аннотацию, если вы не установите флаг в значение true.Свойство jsr250Enabled обеспечивает поддержку аннотации
@RolesAllowed. Поддержка означает, что Spring будет игнорировать эту аннотацию, если вы не установите флаг в значение true.
В чем разница между @PreAuthorize, @Secured и @RolesAllowed?
@Secured и @RolesAllowed в основном одинаковы, хотя @Secured – это специфичная для Spring аннотация, поставляемая с зависимостью spring-security-core, а @RolesAllowed – стандартизированная аннотация, существующая в зависимости javax.annotation-api. Обе аннотации принимают в качестве значения строку полномочий/ролей.
@Предварительная авторизация/@Поставторизация также (новее) Аннотации, специфичные для Spring, и более мощные, чем приведенные выше аннотации, поскольку они могут содержать не только полномочия/роли, но также любое допустимое выражение орфографии.
Наконец, все эти аннотации вызовут исключение AccessDeniedException если вы попытаетесь получить доступ к защищенному методу с недостаточными полномочиями/ролью.
Итак, давайте наконец посмотрим на эти аннотации в действии.
@Service
public class SomeService {
@Secured("ROLE_CALLCENTER")
// == @RolesAllowed("ADMIN")
public BankAccountInfo get(...) {
}
@PreAuthorize("isAnonymous()")
// @PreAuthorize("#contact.name == principal.name")
// @PreAuthorize("ROLE_ADMIN")
public void trackVisit(Long id);
}
}
Как уже упоминалось, @Secured принимает полномочия/роль в качестве параметра. @RolesAllowed, аналогично. Примечание : Помните, что
@RolesAllowed("АДМИНИСТРАТОР")будет проверять наличие предоставленных полномочийROLE_ADMIN.Как уже упоминалось, @PreAuthorize принимает полномочия, а также любое допустимое выражение орфографии. Для получения списка распространенных встроенных выражений безопасности, таких как
is Anonymous()выше, в отличие от написания собственных выражений орфографии, ознакомьтесь с официальной документацией .
Какую аннотацию я должен использовать?
В основном это вопрос однородности, а не слишком привязки к API-интерфейсам, специфичным для Spring (аргумент, который часто выдвигается).
Если вы используете @Secured, придерживайтесь его и не используйте аннотацию @RolesAllowed в 28% других ваших компонентов, пытаясь стандартизировать , но никогда полностью не справляется.
Для начала вы всегда можете использовать @Secure и переключиться на @PreAuthorize, как только возникнет необходимость.
Spring Security и Spring Web MVC
Что касается интеграции с Spring WebMVC, Spring Security позволяет вам сделать несколько вещей:
В дополнение к сопоставителям муравьев и сопоставителям регулярных выражений вы также можете использовать совпадения mvc. Разница в том, что в то время как antMatchers и regexmatchers в основном сопоставляют строки URI с подстановочными знаками, MVCMATCHERS ведут себя точно как @RequestMappings.
Внедрение вашего в настоящее время аутентифицированного участника в метод @Controller/@RestController.
Внедрение токена CSRF вашего текущего сеанса в метод @Controller/@RestController.
Правильная обработка безопасности для асинхронной обработки запросов .
@Controller
public class MyController {
@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser customUser, CsrfToken token) {
// .. find messages for this user and return them ...
}
}
@AuthenticationPrincipal введет участника, если пользователь аутентифицирован, или null, если пользователь не аутентифицирован. Этот принципал является объектом, поступающим от вашего менеджера пользовательских данных/аутентификации!
Или вы можете ввести токен CSRF текущего сеанса в каждый метод.
Если вы не используете аннотацию @authenticationprincipal, вам придется самостоятельно получить участника через SecurityContextHolder. Техника, часто встречающаяся в устаревших приложениях безопасности Spring.
@Controller
public class MyController {
@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(CsrfToken token) {
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof UserDetails) {
CustomUser customUser = (CustomUser) authentication.getPrincipal();
// .. find messages for this user and return them ...
}
// todo
}
}
Пружинная защита и Пружинный ботинок
Spring Boot действительно только предварительно настраивает Spring Security для вас, всякий раз, когда вы добавляете зависимость spring-boot-starter-security в свой проект Spring Boot.
Кроме этого, вся конфигурация безопасности выполняется с использованием простых концепций безопасности Spring (подумайте: WebSecurityConfigurerAdapter, правила аутентификации и авторизации), которые не имеют ничего общего с загрузкой Spring как таковой.
Итак, все, что вы прочитали в этом руководстве, относится 1:1 к использованию Spring Security с Spring Boot. И если вы не разбираетесь в простой безопасности, не надейтесь правильно понять, как обе технологии работают вместе.
Пружинная защита и вилочковый лист
Spring Security хорошо интегрируется с Thymeleaf. Он предлагает специальный диалект Spring Security Thymeleaf, который позволяет вам помещать выражения безопасности непосредственно в ваши HTML-шаблоны Thymeleaf.
This content is only shown to authenticated users.This content is only shown to administrators.This content is only shown to users.
Для получения полного и более подробного обзора того, как обе технологии работают вместе, ознакомьтесь с официальной документацией .
часто задаваемые вопросы
Какова последняя версия Spring Security?
По состоянию на апрель 2020 года это {springsecurityversion}.
Обратите внимание, что если вы используете зависимости безопасности Spring, определенные Spring Boot, у вас может быть немного более старая версия безопасности Spring, например 5.2.1.
Совместимы ли более старые версии Spring Security с последней версией?
В последнее время Spring Security претерпевает довольно серьезные изменения. Поэтому вам нужно будет найти руководства по миграции для ваших целевых версий и проработать их:
Пружинная защита от 3.x до 4.x → https://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-jc.html
Пружинная защита от 4.x до 5.x(< 5.3) → https://docs.spring.io/spring-security/site/docs/5.0.15.RELEASE/reference/htmlsingle/#new (не настоящий путеводитель, но что нового)
Пружинная защита от 5.x до 5.3 → https://docs.spring.io/spring-security/site/docs/5.3.1.RELEASE/reference/html5/#new (не настоящий путеводитель, но что нового)
Какие зависимости мне нужно добавить для работы Spring Security?
Простой Весенний проект
Если вы работаете с простым проектом Spring ( не Spring Boot), вам необходимо добавить в свой проект следующие две зависимости Maven/Gradle:
org.springframework.security spring-security-web 5.2.2.RELEASE org.springframework.security spring-security-config 5.2.2.RELEASE
Вам также потребуется настроить цепочку фильтров безопасности в вашем web.xml или конфигурация Java. Посмотрите, как это сделать здесь .
Проект весеннего ботинка
Если вы работаете с проектом Spring Boot, вам необходимо добавить в свой проект следующую зависимость Maven/Gradle:
org.springframework.boot spring-boot-starter-security
Все остальное будет автоматически настроено для вас, и вы можете немедленно приступить к написанию своего WebSecurityConfigurerAdapter.
Как мне получить программный доступ к текущему аутентифицированному пользователю в Spring Security?
Как упоминалось в статье, Spring Security хранит текущего аутентифицированного пользователя (или, скорее, Контекст безопасности) в локальной переменной потока внутри SecurityContextHolder. Вы можете получить к нему доступ следующим образом:
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection extends GrantedAuthority> authorities = authentication.getAuthorities();
Обратите внимание, что Spring Security по умолчанию установит Анонимный токен аутентификации в качестве аутентификации на держателе SecurityContextHolder, если вы не вошли в систему. Это приводит к некоторой путанице, так как люди, естественно, ожидают там нулевого значения.
Муравьеды: Распространенные примеры
Бессмысленный пример, показывающий наиболее полезные возможности сопоставителей муравьев (и сопоставителей регулярных выражений/mvcMatcher):
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/user/**", "/api/ticket/**", "/index").hasAuthority("ROLE_USER")
.antMatchers(HttpMethod.POST, "/forms/**").hasAnyRole("ADMIN", "CALLCENTER")
.antMatchers("/user/**").access("@webSecurity.check(authentication,request)");
}
Как использовать пользовательскую страницу входа в систему с Spring Security?
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll();
}
- URL-адрес вашей пользовательской страницы входа в систему. Как только вы укажете это, автоматически сгенерированная страница входа исчезнет.
Как выполнить программный вход в систему с помощью Spring Security?
UserDetails principal = userDetailsService.loadUserByUsername(username);
Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), principal.getAuthorities());
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);
Как отключить CSRF только для определенных путей?
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().ignoringAntMatchers("/api/**");
}
Плавник
Если вы прочитали это далеко, теперь у вас должно быть довольно хорошее представление о сложности экосистемы безопасности Spring, даже без OAuth2. Подведем итоги:
Это поможет, если у вас есть базовое представление о том, как работает цепочка фильтров Spring Security и каковы ее средства защиты от эксплойтов по умолчанию (например, CSRF).
Убедитесь, что вы понимаете разницу между аутентификацией и авторизацией. Также, какие @ компоненты вам нужно указать для конкретных рабочих процессов аутентификации.
Убедитесь, что вы понимаете DSL Spring Security Websecurityconfigureradapter, а также безопасность методов на основе аннотаций.
И последнее, но не менее важное: это помогает перепроверить интеграцию Spring Security с другими фреймворками и библиотеками, такими как Spring MVC или Thymeleaf.
Хватит на сегодня, так как это была отличная поездка, не так ли? Спасибо за чтение!
Подтверждения
Большое “спасибо” Патрисио “Пато” Мошковичу , который не только сделал корректуру для этой статьи, но и предоставил бесценный отзыв!
Больше
Вас также может заинтересовать мой недавно анонсированный курс Spring Security exercise , который будет обучать Spring Security и OAuth2 довольно уникальным способом.
Оригинал: “https://dev.to/marcobehler/spring-security-authentication-and-authorization-in-depth-m9g”