Фреймворк Spring Security кажется сложным, но в конечном итоге различные функции безопасности в фреймворке реализуются в основном с помощью так называемой «цепочки фильтров», состоящей из фильтров (javax.servlet.Filter). Эти фильтры реализованы в цепочке. Шаблоны проектирования организованы и взаимосвязаны, но когда вы впервые знакомитесь с инфраструктурой Spring Security, вам не нужно сосредотачиваться на изучении каждого фильтра. Наша первая цель — научиться использовать Spring. Безопасность настроена. Многие люди, особенно новички, будут чувствовать необъяснимое замешательство в отношении этого метода http.build() без достаточных базовых знаний после прочтения кода примера конфигурации (как показано ниже) в официальной документации. Я не знаю, с чего начать. если я хочу настроить разработку. В этой статье в основном анализируется весь процесс настройки Spring Security. Я надеюсь, что она будет полезна студентам, изучающим среду Spring Sercurity.
Примечание по версии: каждый исходный код, опубликованный ниже, получен из версии 6.2.3. Однако на самом деле код, связанный с конфигурацией каждой версии выше 5.7, в основном одинаков, и изменения не слишком велики.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.formLogin(withDefaults())
.httpBasic(withDefaults());
return http.build();
}
Вообще говоря,Процесс настройки HttpSecurity,Главное добавить в этот SecurityFilterChian объекты Filter с разными функциями.,Чтобы облегчить понимание следующих,Во-первых, давайте взглянем на несколько важных и добрых интерфейсов (взаимосвязь показана ниже).
Следующий,Сосредоточьтесь на анализе AbstractConfiguredSecurityBuilderдобрый,Весь процесс сборки вращается вокруг метода doBuild.,В основном делится на:
И вAbstractConfiguredSecurityBuilderПоддерживается один вMap>объект,Реализация для кэширования различных SecurityConfigures добрый,При вызове init и configure,Фактически будут пройдены все конфигураторы этой Карты.,Последовательный вызов соответствующего метода,Обычно в методе configure,Добавьте фильтр в FilterChain (подробно ниже)
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. Исходный код выглядит следующим образом.
@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, полученный по умолчанию, будет выглядеть следующим образом. Давайте сначала получим обзор, а затем проведем углубленный анализ некоторых важных фильтров.
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
В качестве примера мы возьмем пример кода, настроенный в официальной документации Spring Security. Код конфигурации состоит всего из нескольких строк и является относительно элегантным. Эту конструкцию стоит изучить. Попробуйте инкапсулировать сложную логику конфигурации, чтобы разработчики могли использовать ее только тогда, когда это необходимо. используя его, просто сосредоточьтесь на бизнес-логике.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.formLogin(withDefaults())
.httpBasic(withDefaults());
return http.build();
}
Spring Безопасность предоставляет два способа настройки. Один из них — в примере кода, который использует лямбда-выражения для реализации логики конфигурации. До этого для получения объекта конфигурации использовался метод без параметров. , а затем выполните настройку цепочки. Например, приведенный выше пример кода можно переписать как.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.
authorizeHttpRequests().anyRequest().authenticated()
.and().formLogin()
.and().httpBasic();
return http.build();
}
Возьмите авторизе Хттпреквестс в качестве примера, чтобы рассмотреть реализацию исходного кода.,Видно, что эти два метода очень похожи.,Он просто инкапсулируется с использованием интерфейса функции клиента.
@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.
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.
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 используется для инкапсуляции операций, выполняемых после сбоя аутентификации и т. д.
@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, мы можем обратиться к процессу настройки конфигурации в исходном коде, чтобы проанализировать, какие элементы конфигурации. и эти точки конфигурации у них есть. В основном, какие возможности могут быть предоставлены и т. д., чтобы раскрыть идеи и быстро реализовать различные потребности в настройке.
Наконец, сделайте простое резюме, как показано на рисунке:
На этом построение всей цепочки фильтров завершено.