Я понимаю, что безопасность Spring основывается на цепочке фильтров, которые будут перехватывать запрос, обнаруживать (отсутствовать) аутентификацию, перенаправлять на точку входа аутентификации или передавать запрос в службу авторизации и в конечном итоге позволят запросу либо попасть в сервлет, либо выдать исключение безопасности (не авторизованный или не авторизованный). DelegatingFitlerProxy склеивает эти фильтры вместе. Для выполнения своих задач они фильтруют службы доступа, такие как UserDetailsService и AuthenticationManager .
Ключевые фильтры в цепочке есть (в заказе)
- SecurityContextPersistenceFilter (восстанавливает аутентификацию из JSESSIONID)
- UsernamePasswordAuthenticationFilter (выполняет аутентификацию)
- ExceptionTranslationFilter (перехватывать исключения безопасности из FilterSecurityInterceptor)
- FilterSecurityInterceptor (может выдавать исключения аутентификации и авторизации)
Я запутался, как эти фильтры используются. Неужели для весны, предоставленной формы входа в систему, UsernamePasswordAuthenticationFilter используется только для / login , а последние фильтры - нет? Имеет ли форма-Войти элемент пространства имен автоматической настройки этих фильтров? Каждый запрос (аутентифицированный или нет) достигает FilterSecurityInterceptor для URL, не входящего в систему?
Что, если я хочу защитить свой REST API с помощью JWT-токена , который извлекается из логина? Я должен настроить два тега конфигурации пространства имен http
, права? Один для / логин с UsernamePasswordAuthenticationFilter
, а другой для REST URL, с пользовательскими JwtAuthenticationFilter
.
Создает ли настройка двух http
элементов два springSecurityFitlerChains
? Является ли UsernamePasswordAuthenticationFilter
по умолчанию отключено, пока я не объявляю form-login
? Как мне заменить SecurityContextPersistenceFilter
фильтр, который получит Authentication
из существующих, JWT-token
а не JSESSIONID
?
источник
Ответы:
Цепочка фильтров безопасности Spring - очень сложный и гибкий двигатель.
Изучив текущую документацию стабильного выпуска 4.2.1 , раздел 13.3 Упорядочение фильтров, вы можете увидеть организацию фильтров всей цепочки фильтров:
Теперь я постараюсь ответить на ваши вопросы один за другим:
Как только вы настраиваете
<security-http>
раздел, для каждого из них вы должны как минимум предоставить один механизм аутентификации. Это должен быть один из фильтров, которые соответствуют группе 4 в разделе 13.3 «Порядок фильтров» из документации Spring Security, на которую я только что ссылался.Это минимальный действительный элемент безопасности: http, который можно настроить:
Просто сделав это, эти фильтры настраиваются в прокси цепочки фильтров:
Примечание: я получаю их, создав простой RestController, который @Autowires FilterChainProxy и возвращает его содержимое:
Здесь мы можем видеть, что, просто объявив
<security:http>
элемент с одной минимальной конфигурацией, все фильтры по умолчанию включены, но ни один из них не относится к типу аутентификации (4-я группа в разделе 13.3 «Порядок фильтров»). Таким образом, на самом деле это означает, что просто объявивsecurity:http
элемент, SecurityContextPersistenceFilter, ExceptionTranslationFilter и FilterSecurityInterceptor автоматически конфигурируются.Фактически, должен быть настроен один механизм обработки аутентификации, и даже бины пространства имен безопасности обрабатывают заявки на это, выдавая ошибку во время запуска, но это можно обойти, добавив атрибут entry-point-ref в
<http:security>
Если я добавлю базовое
<form-login>
в конфигурацию, то так:Теперь filterChain будет выглядеть так:
Теперь эти два фильтра org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter и org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter создаются и настраиваются в FilterChainProxy.
Итак, теперь вопросы:
Да, он используется, чтобы попытаться завершить механизм обработки входа в систему, если запрос соответствует URL-адресу UsernamePasswordAuthenticationFilter. Этот URL-адрес может быть настроен или даже изменен в соответствии с каждым запросом.
Вы также можете иметь более одного механизма обработки аутентификации, настроенного в одном и том же FilterchainProxy (например, HttpBasic, CAS и т. Д.).
Нет, элемент form-login настраивает UsernamePasswordAUthenticationFilter, и в случае, если вы не предоставляете URL-адрес страницы входа, он также настраивает org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter, который заканчивается простым автоматически сгенерированным входом в систему. стр.
Другие фильтры автоматически настраиваются по умолчанию, просто создав
<security:http>
элемент безsecurity:"none"
атрибута.Каждый запрос должен достигать его, так как это элемент, который заботится о том, имеет ли запрос право на получение запрошенного URL. Но некоторые из фильтров, обработанных ранее, могут остановить обработку цепочки фильтров, просто не вызывая
FilterChain.doFilter(request, response);
. Например, фильтр CSRF может остановить обработку цепочки фильтров, если в запросе отсутствует параметр csrf.Нет, вы не обязаны делать это. Вы можете объявить оба
UsernamePasswordAuthenticationFilter
и один иJwtAuthenticationFilter
тот же элемент http, но это зависит от конкретного поведения каждого из этих фильтров. Оба подхода возможны, и какой из них выбрать в конечном итоге зависит от собственных предпочтений.Да, это правда
Да, вы могли видеть это в фильтрах, поднятых в каждом из конфигов, которые я выложил
Вы можете избежать SecurityContextPersistenceFilter, просто настроив стратегию сессии в
<http:element>
. Просто настройте так:<security:http create-session="stateless" >
Или, в этом случае вы можете перезаписать его другим фильтром, вот так внутри
<security:http>
элемента:РЕДАКТИРОВАТЬ:
Наконец, это зависит от реализации каждого фильтра, но верно то, что последние фильтры аутентификации, по крайней мере, способны перезаписывать любую предыдущую аутентификацию, в конечном итоге выполненную предыдущими фильтрами.
Но это не обязательно произойдет. У меня есть несколько производственных случаев в защищенных REST-сервисах, где я использую токен авторизации, который может быть предоставлен как в виде заголовка Http, так и внутри тела запроса. Поэтому я настраиваю два фильтра, которые восстанавливают этот токен, в одном случае из заголовка Http, а в другом - из тела запроса собственного запроса покоя. Это правда, что если один http-запрос предоставляет этот токен аутентификации как в виде заголовка Http, так и внутри тела запроса, оба фильтра будут пытаться выполнить механизм аутентификации, делегируя его менеджеру, но этого можно легко избежать, просто проверяя, является ли запрос уже аутентифицированы только в начале
doFilter()
метода каждого фильтра.Наличие более одного фильтра аутентификации связано с наличием более одного поставщика аутентификации, но не форсируйте его. В случае, который я описал ранее, у меня есть два фильтра аутентификации, но у меня есть только один поставщик аутентификации, так как оба фильтра создают объект аутентификации одного типа, поэтому в обоих случаях менеджер аутентификации делегирует его одному и тому же поставщику.
И напротив, у меня тоже есть сценарий, в котором я публикую только один UsernamePasswordAuthenticationFilter, но учетные данные пользователя могут содержаться в БД или LDAP, поэтому у меня есть два поддерживаемых провайдера UsernamePasswordAuthenticationToken, и AuthenticationManager делегирует любую попытку аутентификации от фильтра поставщикам последовательно проверять полномочия.
Поэтому я думаю, что ясно, что ни количество фильтров аутентификации не определяет количество поставщиков аутентификации, ни количество провайдеров не определяет количество фильтров.
Раньше я не внимательно изучал этот фильтр, но после вашего последнего вопроса я проверял его реализацию, и, как обычно в Spring, почти все можно было настроить, расширить или переписать.
В SecurityContextPersistenceFilter делегаты в SecurityContextRepository реализации Поиски SecurityContext. По умолчанию используется HttpSessionSecurityContextRepository , но это можно изменить с помощью одного из конструкторов фильтра. Поэтому может быть лучше написать SecurityContextRepository, который соответствует вашим потребностям, и просто настроить его в SecurityContextPersistenceFilter, полагаясь на его проверенное поведение, а не начинать все с нуля.
источник
No qualifying bean of type 'org.springframework.security.web.FilterChainProxy' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Нет,
UsernamePasswordAuthenticationFilter
расширяетAbstractAuthenticationProcessingFilter
, и это содержитRequestMatcher
, что означает, что вы можете определить свой собственный URL-адрес обработки, этот фильтр обрабатывает толькоRequestMatcher
совпадения URL-адреса запроса, URL-адрес обработки по умолчанию -/login
.Более поздние фильтры все еще могут обрабатывать запрос, если он
UsernamePasswordAuthenticationFilter
выполняетсяchain.doFilter(request, response);
.Подробнее о сборщиках сердечника
UsernamePasswordAuthenticationFilter
создается<form-login>
, это стандартный фильтр Псевдонимы и заказЭто зависит от того, успешны ли ранее установщики, но
FilterSecurityInterceptor
обычно ли это последний установщик.Да, у каждого fitlerChain есть
RequestMatcher
, если онRequestMatcher
соответствует запросу, запрос будет обработан установщиками в цепочке соответствия.По умолчанию
RequestMatcher
соответствует всем запросам, если вы не настроили шаблон, или вы можете настроить конкретный URL (<http pattern="/rest/**"
).Если вы хотите узнать больше о сборщиках, я думаю, вы можете проверить исходный код в Spring Security.
doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
источник
Spring security - это основанная на фильтрах инфраструктура, которая устанавливает WALL (HttpFireWall) перед вашим приложением в терминах прокси-фильтров или bean-компонентов, управляемых Spring. Ваш запрос должен пройти через несколько фильтров, чтобы добраться до вашего API.
Последовательность выполнения в Spring Security
WebAsyncManagerIntegrationFilter
Обеспечивает интеграцию между SecurityContext и WebAsyncManager Spring Web.SecurityContextPersistenceFilter
Этот фильтр будет выполняться только один раз для каждого запроса, заполняет SecurityContextHolder информацией, полученной из сконфигурированного SecurityContextRepository до запроса, и сохраняет ее в хранилище после завершения запроса и очистки держателя контекста.Запрос проверен на существующий сеанс. Если новый запрос, SecurityContext будет создан в противном случае, если запрос имеет сеанс, тогда существующий контекст безопасности будет получен из репозитория .
HeaderWriterFilter
Реализация фильтра для добавления заголовков к текущему ответу.LogoutFilter
Если URL-адрес запроса/logout
(для конфигурации по умолчанию) или если в запросеRequestMatcher
настроены выражения URL-адресов,LogoutConfigurer
тоLogoutConfigurer
/
выхода из системы или настроенный URL-адрес выхода из системы или вызывает настроенный logoutSuccessHandler.UsernamePasswordAuthenticationFilter
HTTP POST
) по умолчанию/login
или спички ,.loginProcessingUrl()
настроенные вFormLoginConfigurer
тоUsernamePasswordAuthenticationFilter
аутентификации попыток.usernameParameter(String)
,passwordParameter(String)
..loginPage()
переопределений по умолчаниюAuthentication
объект (UsernamePasswordAuthenticationToken
или любая реализацияAuthentication
в случае пользовательского фильтра AUTH) создается.authenticationManager.authenticate(authToken)
будет вызванAuthenticationProvider
проверки подлинности, которые проверяются всеми провайдерами аутентификации, и проверяют любойsupports
объект authToken / authentication провайдера аутентификации, для аутентификации будет использоваться поддерживающий провайдер аутентификации. и возвращает объект Аутентификация в случае успешной аутентификации, которую еще выбрасываетAuthenticationException
.authenticationSuccessHandler
будет вызвана, которая перенаправляет на целевой URL-адрес настроен (по умолчанию это/
)SecurityContextHolderAwareRequestFilter
, если вы используете его для установки HttpServletRequestWrapper с поддержкой Spring Security в свой контейнер сервлетаAnonymousAuthenticationFilter
Определяет, нет ли объекта Security Authentication в SecurityContextHolder, если объект аутентификации не найден, создаетAuthentication
object (AnonymousAuthenticationToken
) с предоставленными полномочиямиROLE_ANONYMOUS
. ЭтоAnonymousAuthenticationToken
облегчает выявление неаутентифицированных пользователей последующих запросов.ExceptionTranslationFilter
для перехвата любых исключений Spring Security, чтобы можно было либо вернуть ответ об ошибке HTTP, либо запустить соответствующий AuthenticationEntryPointFilterSecurityInterceptor
В
FilterSecurityInterceptor
цепочке фильтров будет происходить последнее, которое будет последним, которое получает объект проверки подлинностиSecurityContext
и получает список предоставленных прав доступа (роли предоставлены), и оно примет решение, разрешить ли этот запрос достичь запрошенного ресурса, или нет, решение принимается путем сопоставления с разрешеноAntMatchers
настроено вHttpSecurityConfiguration
.Рассмотрим исключения 401-UnAuthorized и 403-Forbidden. Эти решения будут приняты последними в цепочке фильтров
Примечание: Запрос пользователя потоки не только в упомянутых выше фильтров, но есть и другие фильтры тоже не показанные здесь (.
ConcurrentSessionFilter
,RequestCacheAwareFilter
,SessionManagementFilter
...)Это будет отличаться , если вы используете пользовательские аутентификации фильтр вместо
UsernamePasswordAuthenticationFilter
.Он будет другим, если вы настроите фильтр аутентификации JWT и опустите
.formLogin() i.e, UsernamePasswordAuthenticationFilter
его, что станет совершенно другим случаем.Просто для справки. Фильтры в Spring-Web и Spring-Security.
Примечание: укажите имя пакета в рис. , Так как есть некоторые другие фильтры из orm и мой собственный реализованный фильтр.
Вы также можете назвать
наиболее распространенный способ аутентификации современного веб-приложения?
разница между аутентификацией и авторизацией в контексте Spring Security?
источник