Статья Spring Security 6.x для быстрого понимания принципов настройки
Статья Spring Security 6.x для быстрого понимания принципов настройки

1. Основные понятия

Фреймворк Spring Security кажется сложным, но в конечном итоге различные функции безопасности в фреймворке реализуются в основном с помощью так называемой «цепочки фильтров», состоящей из фильтров (javax.servlet.Filter). Эти фильтры реализованы в цепочке. Шаблоны проектирования организованы и взаимосвязаны, но когда вы впервые знакомитесь с инфраструктурой Spring Security, вам не нужно сосредотачиваться на изучении каждого фильтра. Наша первая цель — научиться использовать Spring. Безопасность настроена. Многие люди, особенно новички, будут чувствовать необъяснимое замешательство в отношении этого метода http.build() без достаточных базовых знаний после прочтения кода примера конфигурации (как показано ниже) в официальной документации. Я не знаю, с чего начать. если я хочу настроить разработку. В этой статье в основном анализируется весь процесс настройки Spring Security. Я надеюсь, что она будет полезна студентам, изучающим среду Spring Sercurity.

Примечание по версии: каждый исходный код, опубликованный ниже, получен из версии 6.2.3. Однако на самом деле код, связанный с конфигурацией каждой версии выше 5.7, в основном одинаков, и изменения не слишком велики.

Язык кода:java
копировать
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
            .authorizeHttpRequests(authorize -> authorize
                    .anyRequest().authenticated()
            )
            .formLogin(withDefaults())
            .httpBasic(withDefaults());
    return http.build();
}

Вообще говоря,Процесс настройки HttpSecurity,Главное добавить в этот SecurityFilterChian объекты Filter с разными функциями.,Чтобы облегчить понимание следующих,Во-первых, давайте взглянем на несколько важных и добрых интерфейсов (взаимосвязь показана ниже).

интерфейс

  • SecurityBuilder: интерфейс верхнего уровня, определяет абстрактный универсальный метод конструктора — build().
  • SecurityConfigurer: интерфейс верхнего уровня,Общий метод, используемый для определения конфигурации,Каждый фильтр создается на основе определенной доброй реализации SecurityConfigurer и добавляется в FilterChain.
  • SecurityFilterChain: интерфейс верхнего уровня.,то есть цепочка фильтров,определен метод, который получает список,и спички,Используется для определения соответствия запроса условиям перехода по ссылке.
  • HttpSecurityBuilder: Приложение SecurityBuilder,Определяет различные вспомогательные функции в процессе построения SecurityFilterChain.,Например, добавление фильтра в SecurityFilterChain.,Получить реализацию конфигурации SecurityConfigurer добрый и т.д.

добрый

  • AbstractSecurityBuilder: добрый абстрактный родительский элемент верхнего уровня.,Он не реализует конкретную логику сборки,Фактическая реализация осуществляется методом doBuild.,Просто используйте CAS для управления параллелизмом процесса doBuild.
  • AbstractConfiguredSecurityBuilder: приложение AbstractConfiguredSecurityBuilder,Он поддерживает внутренний список SecurityConfigurers.,реализован метод doBuild,Налажен весь процесс строительства
  • HttpSecurity реализован как финальный добрый,В основном это для разработчиков,Мы используем ряд записей конфигурации, которые он предоставляет в процессе разработки.,Разработчикам удобно настраивать различные фильтры в SecurityFilterChain.,Включая добавление пользовательского фильтра,Закрыть некоторые фильтры,Или расширить возможности оригинального Фильтра и т.п.

2. Основной процесс

Следующий,Сосредоточьтесь на анализе AbstractConfiguredSecurityBuilderдобрый,Весь процесс сборки вращается вокруг метода doBuild.,В основном делится на:

  1. инициализация,Включая beforeInit и initметод,Среди них beforeInit — это перехватчик, используемый для метода расширения.,Реализация по умолчанию пуста
  2. Конфигурация,Включая метод beforeConfigure и configure,Среди них beforeConfigure — это ловушка для метода расширения.,Реализация по умолчанию пуста
  3. структура,т. е. выполнить методBuild,Специально реализовано HttpSecurity,В основном для сортировки фильтра,и, наконец, возвращает экземпляр DefaultSecurityFilterChain.

И вAbstractConfiguredSecurityBuilderПоддерживается один вMap>объект,Реализация для кэширования различных SecurityConfigures добрый,При вызове init и configure,Фактически будут пройдены все конфигураторы этой Карты.,Последовательный вызов соответствующего метода,Обычно в методе configure,Добавьте фильтр в FilterChain (подробно ниже)

Язык кода:java
копировать
protected final O doBuild() throws Exception {
    synchronized (this.configurers) {
       this.buildState = BuildState.INITIALIZING;
       beforeInit();
       init();
       this.buildState = BuildState.CONFIGURING;
       beforeConfigure();
       configure();
       this.buildState = BuildState.BUILDING;
       O result = performBuild();
       this.buildState = BuildState.BUILT;
       return result;
    }
}
 
private void configure() throws Exception {
    Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
    for (SecurityConfigurer<O, B> configurer : configurers) {
       configurer.configure((B) this);
    }
}

Итак, как эти экземпляры SecurityConfigure добавляются на приведенную выше карту? Соответствующую реализацию можно найти в HttpSecurityConfiguration. Исходный код выглядит следующим образом.

Язык кода:java
копировать
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
HttpSecurity httpSecurity() throws Exception {
    LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context);
    AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(
          this.objectPostProcessor, passwordEncoder);
    authenticationBuilder.parentAuthenticationManager(authenticationManager());
    authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher());
    HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
    WebAsyncManagerIntegrationFilter webAsyncManagerIntegrationFilter = new WebAsyncManagerIntegrationFilter();
    webAsyncManagerIntegrationFilter.setSecurityContextHolderStrategy(this.securityContextHolderStrategy);
    // @formatter:off
    http
       .csrf(withDefaults())
       .addFilter(webAsyncManagerIntegrationFilter)
       .exceptionHandling(withDefaults())
       .headers(withDefaults())
       .sessionManagement(withDefaults())
       .securityContext(withDefaults())
       .requestCache(withDefaults())
       .anonymous(withDefaults())
       .servletApi(withDefaults())
       .apply(new DefaultLoginPageConfigurer<>());
    http.logout(withDefaults());
    // @formatter:on
    applyCorsIfAvailable(http);
    applyDefaultConfigurers(http);
    return http;
}

Вы можете видеть, что в процессе построения (эта конфигурация длинной цепочки) для нас было добавлено несколько экземпляров SecurityConfguurer. Поэтому, когда мы используем и настраиваем SecurityFilterChain, нам нужно совсем немного конфигурации, чтобы получить полную версию SecurityFilterChain. конечно, мы также можем использовать эти элементы конфигурации для выполнения множества индивидуальных разработок. Фактически HttpSecurity предоставляет примерно 24 метода настройки Конфигуратора, связанных с фильтрами, 11 из которых загружаются по умолчанию и организованы в таблицу:

серийный номер

метод

Соответствует фильтру

эффект

1

headers

HeaderWriterFilter (загружается по умолчанию)

Используется для добавления HTTP-заголовка безопасности в ответ, например X-Frame-Options.

2

cors

CorsFilter (обычно загружается по умолчанию в среде Spring MVC)

Используется для поддержки междоменных запросов.

3

sessionManagement

SessionManagementFilterConcurrentSessionFilterDisableEncodeUrlFilter(Действует по умолчанию)ForceEagerSessionCreationFilter

Используется для управления сеансами, например сохранения сеансов, управления параллельным доступом и других операций.

4

jee

J2eePreAuthenticatedProcessingFilter

Используется для поддержки предварительной сертификации контейнера Java EE.

5

x509

X509AuthenticationFilter

Используется для поддержки предварительной аутентификации сертификата X.509, обычно имеется в виду использование протокола HTTPS в браузере.

6

rememberMe

RememberMeAuthenticationFilter

Используется для записи информации о входе пользователя при входе в систему для поддержания статуса входа.

7

authorizeHttpRequests

AuthorizationFilter

Логика, используемая для реализации авторизованного доступа

8

requestCache

RequestCacheAwareFilter (загружается по умолчанию)

Используется для реализации того, что после входа пользователя в систему он возвращается к адресу, запрошенному перед входом в систему.

9

exceptionHanding

ExceptionTranslationFilter (загружается по умолчанию)

Используется для настройки обработки исключений˛

10

securityContext

SecurityContextHolderFilter (загружается по умолчанию) SecurityContextPersistenceFilter (старая версия, сейчас устарела)

Используется для загрузки информации о статусе входа пользователя и сохранения ее в SecurityContextHolder.

11

servletApi

SecurityContextHolderAwareRequestFilter (загружается по умолчанию)

Используется для переноса HttpServletRequest в Servlet3SecurityContextHolderAwareRequestWrapper для облегчения использования других фильтров.

12

csrf

CsrfFilter (загружается по умолчанию)

Используется для предотвращения атак с подделкой межсайтовых запросов (CSRF).

13

logout

LogoutFilter (загружается по умолчанию)

Используется для реализации логики выхода из системы и выхода из системы.

14

anonymous

AnonymousAuthenticationFilter (загружается по умолчанию)

Используется для реализации логики анонимного входа.

15

formLogin

UsernamePasswordAuthenticationFilter

Используется для реализации логики входа в систему с именем пользователя и паролем.

16

saml2Login

Saml2WebSsoAuthenticationFilter

Используется для реализации логики входа в систему по протоколу аутентификации SAML 2.0.

17

saml2Logout

Saml2LogoutRequestFilterSaml2LogoutResponseFilterSaml2RelyingPartyInitiatedLogoutFilter

Используется для реализации логики выхода из протокола аутентификации SAML 2.0.

18

oauth2Login

OAuth2AuthorizationRequestRedirectFilter

Используется для доступа к логике входа в протокол аутентификации OAuth2.0, например входу в Github.

19

oidcLogout

OidcBackChannelLogoutFilter

Используется для реализации логики выхода из протокола аутентификации OIDC.

20

oauth2Client

OAuth2AuthorizationRequestRedirectFilterOAuth2AuthorizationCodeGrantFilter

Используется для реализации клиентской логики OAuth2.0, такой как режим кода авторизации и т. д.

21

oauth2ResourceServer

BearerTokenAuthenticationFilter

Используется для реализации серверной логики OAuth2.0.

22

requiresChannel

ChannelProcessingFilter

Используется для определения того, какие ресурсы необходимо защитить.

23

httpBasic

BasicAuthenticationFilter

Логика, используемая для реализации базовой аутентификации HTTP

24

passwordManagement

RequestMatcherRedirectFilter("/change-password")

Используется для реализации логики перехода на страницу при необходимости смены пароля.

25

HttpSecurityConfiguraion добавлен напрямую.

WebAsyncManagerIntegrationFilter (загружается по умолчанию)

Используется в асинхронных потоках для поддержки получения объекта аутентификации. Аутентификация через SecurityContextHolder.

Если мы не вносим никаких изменений в HttpSecurity, то SecurityFilterChain, полученный по умолчанию, будет выглядеть следующим образом. Давайте сначала получим обзор, а затем проведем углубленный анализ некоторых важных фильтров.

Язык кода:txt
копировать
org.springframework.security.web.session.DisableEncodeUrlFilter
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter
org.springframework.security.web.context.SecurityContextHolderFilter
org.springframework.security.web.header.HeaderWriterFilter
org.springframework.web.filter.CorsFilter
org.springframework.security.web.csrf.CsrfFilter
org.springframework.security.web.authentication.logout.LogoutFilter
org.springframework.security.web.savedrequest.RequestCacheAwareFilter
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
org.springframework.security.web.authentication.AnonymousAuthenticationFilter
org.springframework.security.web.access.ExceptionTranslationFilter

3. Пример SecurityConfigurer

В качестве примера мы возьмем пример кода, настроенный в официальной документации Spring Security. Код конфигурации состоит всего из нескольких строк и является относительно элегантным. Эту конструкцию стоит изучить. Попробуйте инкапсулировать сложную логику конфигурации, чтобы разработчики могли использовать ее только тогда, когда это необходимо. используя его, просто сосредоточьтесь на бизнес-логике.

Язык кода:java
копировать
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
            .authorizeHttpRequests(authorize -> authorize
                    .anyRequest().authenticated()
            )
            .formLogin(withDefaults())
            .httpBasic(withDefaults());
    return http.build();
}

Spring Безопасность предоставляет два способа настройки. Один из них — в примере кода, который использует лямбда-выражения для реализации логики конфигурации. До этого для получения объекта конфигурации использовался метод без параметров. , а затем выполните настройку цепочки. Например, приведенный выше пример кода можно переписать как.

Язык кода:java
копировать
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.
            authorizeHttpRequests().anyRequest().authenticated()
            .and().formLogin()
            .and().httpBasic();
    return http.build();

}

Возьмите авторизе Хттпреквестс в качестве примера, чтобы рассмотреть реализацию исходного кода.,Видно, что эти два метода очень похожи.,Он просто инкапсулируется с использованием интерфейса функции клиента.

Язык кода:java
копировать
@Deprecated(since = "6.1", forRemoval = true)
public AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry authorizeHttpRequests()
       throws Exception {
    ApplicationContext context = getContext();
    return getOrApply(new AuthorizeHttpRequestsConfigurer<>(context)).getRegistry();
}

public HttpSecurity authorizeHttpRequests(
       Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry> authorizeHttpRequestsCustomizer)
       throws Exception {
    ApplicationContext context = getContext();
    authorizeHttpRequestsCustomizer
       .customize(getOrApply(new AuthorizeHttpRequestsConfigurer<>(context)).getRegistry());
    return HttpSecurity.this;
}

где getOrApplyметод,Используется для получения конкретного экземпляра Конфигуратора (выше упоминалось, что Карта Конфигураторов поддерживается в AbstractConfiguredSecurityBuilder).,Эти экземпляры конфигуратора получены из этой карты)

Однако второй способ написания, согласно комментариям в исходниках, должен быть в Spring. Security 7Удален из версии,Так что вам еще придется к этому адаптироватьсяCustomizerпараметрический Конфигурацияметод。

Вышеупомянутый метод авторизацииHttpRequests возвращает объект AuthorizationManagerRequestMatcherRegistry в AuthorizeHttpRequestsConfigurer. Сначала вы можете взглянуть на метод configure в AuthorizeHttpRequestsConfigurer.

Язык кода:java
копировать
public void configure(H http) {
    AuthorizationManager<HttpServletRequest> authorizationManager = this.registry.createAuthorizationManager();
    AuthorizationFilter authorizationFilter = new AuthorizationFilter(authorizationManager);
    authorizationFilter.setAuthorizationEventPublisher(this.publisher);
    authorizationFilter.setShouldFilterAllDispatcherTypes(this.registry.shouldFilterAllDispatcherTypes);
    authorizationFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
    http.addFilter(postProcess(authorizationFilter));
}

Здесь создается AuthorizationFilter,и добавлен в список HttpSecurity.,AuthorizationManagerRequestMatcherRegistry — это еще одна конфигурация, реализованная с помощью шаблона конструктора добрый.,Основная функция — настроить некоторую конкретную логику для перехвата разрешений.,Например, какие адреса требуют доступа, по каким ролям и т.д.,Здесь это не будет расширяться.

Давайте еще раз посмотрим на пример formLogin.

Язык кода:java
копировать
public HttpSecurity formLogin(Customizer<FormLoginConfigurer<HttpSecurity>> formLoginCustomizer) throws Exception {
    formLoginCustomizer.customize(getOrApply(new FormLoginConfigurer<>()));
    return HttpSecurity.this;
}

formLoginметод Пример фактического создания FormLoginConfigurer,Добрый в основном используется для создания UsernamePasswordAuthenticationFilter.,То есть фильтр аутентификации по имени пользователя и паролю по умолчанию.

Метод configure реализует родительский добрыйAbstractAuthenticationFilterConfigurer.,Исходный код выглядит следующим образом,Хотя этот метод немного длинный,Но в основном это связано с настройкой экземпляров UsernamePasswordAuthenticationFilter (this.authFilter — это экземпляр UsernamePasswordAuthenticationFilter,Он создается в конструкторе FormLoginConfigurer),В основном для создания некоторых базовых компонентов, используемых для аутентификации пользователей.,Например, AuthenticationManager используется для инкапсуляции различных методов аутентификации пользователя (таких как имя пользователя и пароль).,AuthenticationSuccessHandler используется для инкапсуляции операций, выполняемых после успешной аутентификации.,AuthenticationFailureHandler используется для инкапсуляции операций, выполняемых после сбоя аутентификации и т. д.

Язык кода:java
копировать
@Override
public void configure(B http) throws Exception {
    PortMapper portMapper = http.getSharedObject(PortMapper.class);
    if (portMapper != null) {
       this.authenticationEntryPoint.setPortMapper(portMapper);
    }
    RequestCache requestCache = http.getSharedObject(RequestCache.class);
    if (requestCache != null) {
       this.defaultSuccessHandler.setRequestCache(requestCache);
    }
    this.authFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
    this.authFilter.setAuthenticationSuccessHandler(this.successHandler);
    this.authFilter.setAuthenticationFailureHandler(this.failureHandler);
    if (this.authenticationDetailsSource != null) {
       this.authFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
    }
    SessionAuthenticationStrategy sessionAuthenticationStrategy = http
       .getSharedObject(SessionAuthenticationStrategy.class);
    if (sessionAuthenticationStrategy != null) {
       this.authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
    }
    RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
    if (rememberMeServices != null) {
       this.authFilter.setRememberMeServices(rememberMeServices);
    }
    SecurityContextConfigurer securityContextConfigurer = http.getConfigurer(SecurityContextConfigurer.class);
    if (securityContextConfigurer != null && securityContextConfigurer.isRequireExplicitSave()) {
       SecurityContextRepository securityContextRepository = securityContextConfigurer
          .getSecurityContextRepository();
       this.authFilter.setSecurityContextRepository(securityContextRepository);
    }
    this.authFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
    F filter = postProcess(this.authFilter);
    http.addFilter(filter);
}

Из двух приведенных выше примеров исходного кода мы видим, что процесс настройки фильтра на самом деле не сложен. Когда мы изучаем различные функции фильтра Spring Security, мы можем обратиться к процессу настройки конфигурации в исходном коде, чтобы проанализировать, какие элементы конфигурации. и эти точки конфигурации у них есть. В основном, какие возможности могут быть предоставлены и т. д., чтобы раскрыть идеи и быстро реализовать различные потребности в настройке.

4. Резюме

Наконец, сделайте простое резюме, как показано на рисунке:

  1. Начните с определения объекта компонента HttpSecurity Bean в HttpSercurityConfiguration.,В HttpSecurity было добавлено несколько объектов SecurityConfigurer.,Кроме того, мы можем настроить Конфигурациядобрый Внесите в него некоторые пользовательские настройки
  2. Затем при вызове метода HttpSecurity#Build(),Все SecurityConfigurers будут получены и пройдены.,Последовательно вызовите соответствующий инициализатор и конфигуратор.,И в конфигураторе,Создание экземпляров фильтров с различными функциями,и добавлен в список списка
  3. Наконец-то прошел метод PerformBuild,Сортировать список,и создайте DefaultSecurityFilterChian

На этом построение всей цепочки фильтров завершено.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose