Как работает цепь фильтра безопасности весны
Я понимаю, что Spring security строится на цепочке фильтров, которые будут перехватывать запрос, обнаруживать (отсутствие) аутентификации, перенаправлять на точку входа аутентификации или передавать запрос в службу авторизации и в конечном итоге позволять запросу либо попадать в сервлет, либо бросать исключение безопасности (неавторизованное или несанкционированное). DelegatingFitlerProxy склеивает эти фильтры вместе. Для выполнения своих задач эти службы фильтрации доступа, такие как UserDetailsService и AuthenticationManager.
ключевые фильтры в цепочке находятся (в порядке)
- SecurityContextPersistenceFilter (восстанавливает аутентификацию из JSESSIONID)
- UsernamePasswordAuthenticationFilter (выполняет аутентификацию)
- ExceptionTranslationFilter (поймать исключения безопасности из FilterSecurityInterceptor)
- FilterSecurityInterceptor (может бросить исключения аутентификации и авторизации)
Я в замешательстве, как эти фильтры используются. Разве что для весны предусмотрена форма-логин,UsernamePasswordAuthenticationFilter используется только для / login, а последних фильтров нет? Делает ли форма входа элемент пространства имен автоматически настраивает эти фильтры? Достигает ли каждый запрос (аутентифицированный или нет) FilterSecurityInterceptor для не-входа URL-адрес?
что делать, если я хочу защитить свой REST API с помощью JWT-token, который извлекается из логина? я должен настроить две конфигурации пространства имен http теги, прав? Другой для / login С UsernamePasswordAuthenticationFilter, и еще один для REST url, с пользовательским JwtAuthenticationFilter.
настройка двух http элементы создают два springSecurityFitlerChains? Это UsernamePasswordAuthenticationFilter выключен по умолчанию, пока я не объявлю form-login? Как мне заменить SecurityContextPersistenceFilter С одной, который получит Authentication из существующих JWT-token, а не JSESSIONID?
2 ответов:
цепь фильтра обеспеченностью весны очень сложный и гибкий двигатель.
ключевые фильтры в цепочке находятся (в порядке)
- SecurityContextPersistenceFilter (восстанавливает аутентификацию из JSESSIONID)
- UsernamePasswordAuthenticationFilter (выполняет аутентификацию)
- ExceptionTranslationFilter (поймать исключения безопасности из FilterSecurityInterceptor)
- FilterSecurityInterceptor (может вызывать исключения аутентификации и авторизации)
смотреть на!--39-->текущая стабильная версия 4.2.1 документация, раздел Фильтр 13.3 Заказ вы можете увидеть всю цепочку фильтров организации фильтра:
Фильтр 13.3 Заказ
порядок, в котором фильтры определяются в цепочке, очень важен. Независимо от того, какие фильтры вы фактически используя, заказ должен быть следующим:
ChannelProcessingFilter, потому что может потребоваться перенаправление на другой протокол
SecurityContextPersistenceFilter, так что SecurityContext может быть настроен в SecurityContextHolder в начале веб-запроса, и любые изменения в SecurityContext могут быть скопированы в HttpSession когда веб-запрос заканчивается (готов к использованию со следующим веб-запросом)
ConcurrentSessionFilter, поскольку он использует функцию SecurityContextHolder и должен обновить SessionRegistry для отражения текущих запросов от участника
механизмы обработки аутентификации - UsernamePasswordAuthenticationFilter, CasAuthenticationFilter, BasicAuthenticationFilter etc-так что SecurityContextHolder может быть изменен, чтобы содержать допустимый токен запроса аутентификации
The SecurityContextHolderAwareRequestfilter, если вы используете его для установки Spring Security aware HttpServletRequestWrapper в свой контейнер сервлетов
The JaasApiIntegrationFilter, если a JaasAuthenticationToken находится в SecurityContextHolder это будет обрабатывать FilterChain как Тема в JaasAuthenticationToken
RememberMeAuthenticationFilter, так что если ранее механизм обработки аутентификации не обновлял SecurityContextHolder, и запрос представляет собой файл cookie, который позволяет помните-мне услуги состоится, подходящий запомненный объект аутентификации будет поставлен там
AnonymousAuthenticationFilter, так что если ранее механизм обработки аутентификации не обновлял SecurityContextHolder, объект анонимной аутентификации будет помещен туда
ExceptionTranslationFilter, чтобы поймать любые весенние исключения безопасности так что либо ответ на ошибку HTTP может быть возвращен, либо соответствующий AuthenticationEntryPoint может быть запущен
FilterSecurityInterceptor, чтобы защитить веб-URI и создавать исключения, когда доступ запрещен
теперь я попытаюсь продолжить ваши вопросы один за другим:
я в замешательстве, как эти фильтры используются. Это что за Весна предоставлена форма-логин, используется только UsernamePasswordAuthenticationFilter для /login, а последние фильтры Нет? Имеет ли пространство имен form-login элемент авто-настройка этих фильтров? Каждый запрос (аутентифицированный или нет) reach FilterSecurityInterceptor для не-входа в систему URL-адрес?
как только вы настраиваете
<security-http>Раздел, для каждого из них вы должны по крайней мере предоставить один механизм аутентификации. Это должен быть один из фильтров, которые соответствуют группе 4 в заказе фильтра 13.3 раздел из документации Spring Security, на которую я только что ссылался.это минимальный допустимый элемент security: http, который можно настроить:
<security:http authentication-manager-ref="mainAuthenticationManager" entry-point-ref="serviceAccessDeniedHandler"> <security:intercept-url pattern="/sectest/zone1/**" access="hasRole('ROLE_ADMIN')"/> </security:http>просто делая это, эти фильтры настраиваются в цепочке фильтров прокси:
{ "1": "org.springframework.security.web.context.SecurityContextPersistenceFilter", "2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter", "3": "org.springframework.security.web.header.HeaderWriterFilter", "4": "org.springframework.security.web.csrf.CsrfFilter", "5": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter", "6": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter", "7": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter", "8": "org.springframework.security.web.session.SessionManagementFilter", "9": "org.springframework.security.web.access.ExceptionTranslationFilter", "10": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor" }Примечание: я получаю их, создавая простой RestController который @Autowires FilterChainProxy и возвращает его содержимое:
@Autowired private FilterChainProxy filterChainProxy; @Override @RequestMapping("/filterChain") public @ResponseBody Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){ return this.getSecurityFilterChainProxy(); } public Map<Integer, Map<Integer, String>> getSecurityFilterChainProxy(){ Map<Integer, Map<Integer, String>> filterChains= new HashMap<Integer, Map<Integer, String>>(); int i = 1; for(SecurityFilterChain secfc : this.filterChainProxy.getFilterChains()){ //filters.put(i++, secfc.getClass().getName()); Map<Integer, String> filters = new HashMap<Integer, String>(); int j = 1; for(Filter filter : secfc.getFilters()){ filters.put(j++, filter.getClass().getName()); } filterChains.put(i++, filters); } return filterChains; }здесь мы могли видеть, что просто объявив
<security:http>элемент при одной минимальной конфигурации включаются все фильтры по умолчанию, но ни один из них не имеет типа аутентификации (4-я группа в разделе 13.3 Filter Ordering). Так что на самом деле это означает, что просто объявивsecurity:httpэлемент, SecurityContextPersistenceFilter, ExceptionTranslationFilter и FilterSecurityInterceptor настраиваются автоматически.фактически, один механизм обработки аутентификации должен быть настроен, и даже компоненты пространства имен безопасности обрабатывают утверждения для это, бросая ошибку во время запуска, но ее можно обойти, добавив атрибут entry-point-ref в
<http:security>если я добавлю базовый
<form-login>конфигурации, таким образом:<security:http authentication-manager-ref="mainAuthenticationManager"> <security:intercept-url pattern="/sectest/zone1/**" access="hasRole('ROLE_ADMIN')"/> <security:form-login /> </security:http>теперь цепочка фильтров будет выглядеть так:
{ "1": "org.springframework.security.web.context.SecurityContextPersistenceFilter", "2": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter", "3": "org.springframework.security.web.header.HeaderWriterFilter", "4": "org.springframework.security.web.csrf.CsrfFilter", "5": "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter", "6": "org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter", "7": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter", "8": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter", "9": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter", "10": "org.springframework.security.web.session.SessionManagementFilter", "11": "org.springframework.security.web.access.ExceptionTranslationFilter", "12": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor" }теперь это два фильтра org.springframework.безопасность.сеть.идентификация.UsernamePasswordAuthenticationFilter и орг.springframework.безопасность.сеть.идентификация.пользовательский интерфейс.DefaultLoginPageGeneratingFilter создаются и настраиваются в FilterChainProxy.
Итак, вопросы:
разве что для весны предусмотрена форма-логин, UsernamePasswordAuthenticationFilter используется только для /login, и последние фильтры не являются?
Да, он используется, чтобы попытаться завершить механизм обработки входа в систему в случае, если запрос соответствует Url-адрес UsernamePasswordAuthenticationFilter. Этот url-адрес можно настроить или даже изменить его поведение, чтобы соответствовать каждому запросу.
у вас также может быть несколько механизмов обработки аутентификации, настроенных в одном FilterchainProxy (например, HttpBasic, CAS и т. д.).
элемент пространства имен form-login автоматически настраивает эти фильтры?
нет, элемент form-login настраивает UsernamePasswordAUthenticationFilter, и если вы не предоставляете url-адрес страницы входа, он также настраивает организацию.springframework.безопасность.сеть.идентификация.пользовательский интерфейс.DefaultLoginPageGeneratingFilter, который заканчивается в простую страницу входа автоматически.
другие фильтры автоматически настраиваются по умолчанию, просто создав
<security:http>элемент без .запрос должен достичь его, так как это элемент, который заботится о том, имеет ли запрос права на доступ к запрошенному url. Но некоторые из фильтров, обработанных ранее, могут остановить обработку цепочки фильтров, просто не вызываякаждый запрос (аутентифицированный или нет) достигает FilterSecurityInterceptor для url-адреса без входа в систему?
FilterChain.doFilter(request, response);. Например, фильтр CSRF может остановить обработку цепочки фильтров, если запрос не имеет параметра csrf.что делать, если я хочу защитить свой REST API с помощью JWT-token, который извлекается из login? Я должен настроить два пространства имен конфигурация http теги, права? Другой для / входа в систему с
UsernamePasswordAuthenticationFilter, и еще один для REST url, с пользовательскимJwtAuthenticationFilter.нет, вы не обязаны делать это таким образом. Вы можете объявить оба
UsernamePasswordAuthenticationFilterиJwtAuthenticationFilterв том же элементе http, но это зависит от конкретного поведения каждого из этих фильтров. Оба подхода возможны, и какой из них выбрать в конечном итоге зависит от собственных предпочтений.выполняет ли настройка двух элементов http создать две springSecurityFitlerChains?
Да, это правда
UsernamePasswordAuthenticationFilter отключен по умолчанию, пока я не объявлю form-login?
Да, вы могли видеть это в фильтрах, поднятых в каждом из конфигураций, которые я опубликовал
как заменить SecurityContextPersistenceFilter на один, который будет получать аутентификацию от существующего JWT-токена, а не JSESSIONID?
вы можете избежать SecurityContextPersistenceFilter, просто настроив сессии стратегии на
<http:element>. Просто настроить следующим образом:
<security:http create-session="stateless" >или, в этом случае вы можете перезаписать его с помощью другого фильтра, таким образом, внутри
<security:http>элемент:<security:http ...> <security:custom-filter ref="myCustomFilter" position="SECURITY_CONTEXT_FILTER"/> </security:http> <beans:bean id="myCustomFilter" class="com.xyz.myFilter" />EDIT:
один вопрос о " вы тоже могли бы иметь несколько механизмов обработки аутентификации настроены в том же FilterchainProxy". Будет ли последний перезаписывать аутентификацию, выполненную первым, если объявить несколько фильтров аутентификации (Spring implementation)? Как это связано с наличием нескольких поставщиков аутентификации?
это, наконец, зависит от реализации самого каждого фильтра, но это правда, что последние фильтры аутентификации, по крайней мере, могут перезаписать любую предыдущую аутентификацию, в конечном итоге сделанную предыдущим фильтры.
но это не обязательно случится. У меня есть некоторые производственные случаи в защищенных службах REST, где я использую своего рода маркер авторизации, который может быть предоставлен как в качестве заголовка Http, так и внутри тела запроса. Поэтому я настраиваю два фильтра, которые восстанавливают этот токен, в одном случае из заголовка Http, а в другом-из тела запроса собственного запроса rest. Это правда, что если один http-запрос предоставляет этот маркер аутентификации как в качестве заголовка Http, так и внутри запроса тело, оба фильтра попытаются выполнить механизм аутентификации, делегируя его менеджеру, но его можно легко избежать, просто проверяя, аутентифицирован ли запрос уже в начале
doFilter()метод каждого фильтра.наличие более чем одного фильтра аутентификации связано с наличием более чем одного поставщика аутентификации, но не заставляйте его. В случае, когда я выставлял ранее, у меня есть два фильтра аутентификации, но у меня есть только один поставщик аутентификации, поскольку оба фильтра создают один и тот же тип объекта проверки подлинности, в обоих случаях диспетчер проверки подлинности делегирует его одному и тому же поставщику.
и напротив этого, у меня тоже есть сценарий, в котором я публикую только один UsernamePasswordAuthenticationFilter, но учетные данные пользователя могут содержаться в DB или LDAP, поэтому у меня есть два поставщика поддержки UsernamePasswordAuthenticationToken, а AuthenticationManager делегирует любую попытку аутентификации от фильтра к серверу. поставщики безопасности для проверки учетных данных.
Итак, я думаю, что ясно, что ни количество фильтров аутентификации не определяет количество поставщиков аутентификации, ни количество поставщиков определяют количество фильтров.
кроме того, в документации указано, что SecurityContextPersistenceFilter отвечает за очистку SecurityContext, что важно из-за объединения потоков. Если я опущу его или предоставлю пользовательскую реализацию, я должен реализовать чистка вручную, верно? Есть еще похожие попался при настройке цепи?
я не смотрел внимательно в этот фильтр раньше, но после вашего последнего вопроса я проверял его реализацию, и, как обычно весной, почти все можно было настроить, расширить или перезаписать.
The SecurityContextPersistenceFilter делегаты в SecurityContextRepository осуществление поиска SecurityContext. По умолчанию HttpSessionSecurityContextRepository, но это может быть изменено с помощью одного из конструкторов фильтра. Поэтому может быть лучше написать SecurityContextRepository, который соответствует вашим потребностям, и просто настроить его в SecurityContextPersistenceFilter, доверяя его доказанному поведению, а не начинать делать все с нуля.
UsernamePasswordAuthenticationFilterиспользуется только для/login, а последних фильтров нет?нет,
UsernamePasswordAuthenticationFilterвыходитAbstractAuthenticationProcessingFilter, и содержитRequestMatcher, это означает, что вы можете определить свой собственный url-адрес обработки, этот фильтр обрабатывает толькоRequestMatcherсопоставляет URL-адрес запроса, URL-адрес обработчика по умолчанию составляет/login.более поздние фильтры все еще могут обрабатывать запрос, если
UsernamePasswordAuthenticationFilterвыполняетchain.doFilter(request, response);.подробнее о ядро fitlers
элемент пространства имен form-login автоматически настраивает эти фильтры?
UsernamePasswordAuthenticationFilterсоздано<form-login>, это стандартные псевдонимы фильтров и порядоккаждый запрос (аутентифицированный или нет) достигает FilterSecurityInterceptor для url-адреса без входа в систему?
это зависит от того, являются ли перед fitlers успешными, но
FilterSecurityInterceptorпоследний фильтровать обычно.настройка двух элементов http создает две springSecurityFitlerChains?
да, каждый fitlerChain имеет
RequestMatcher, еслиRequestMatcherсоответствует запросу, запрос будет обрабатываться fitlers в цепочке fitler.по умолчанию
RequestMatcherсоответствует всем запросам, если вы не настраиваете шаблон, или вы можете настроить конкретный url (<http pattern="/rest/**").если вы хотите узнать больше о fitlers, я думаю вы можете проверить исходный код в spring security.
doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
Comments