Мы переносим большой проект, использующий Spring Security 3.2 с конфигурацией XML, в текущий загрузочный стек Spring с Spring-Security 5.0 и программной конфигурацией.Старый выход работал хорошо, регистрируя обработчик выхода из системы в качестве пользовательского фильтра в конце цепочки фильтров.Соответствующая часть старой xml-конфигурации:
[...]
<http pattern="/oauth/(users|clients)/.*" request-matcher="regex" create-session="stateless" entry-point-ref="oauthAuthenticationEntryPoint" use-expressions="true" xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/oauth/users/revoke" method="POST" access="#oauth2.clientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or #oauth2.isClient())" />
<intercept-url pattern="/**" access="denyAll()" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
<expression-handler ref="oauthWebExpressionHandler" />
<custom-filter ref="revokeFilter" before="LAST" />
</http>
[...]
<bean id="revokeFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg>
<bean class="com.company.management.authorization.oauth2.RevokeSuccessHandler" />
</constructor-arg>
<constructor-arg>
<list>
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
</list>
</constructor-arg>
<property name="filterProcessesUrl" value="/oauth/users/revoke" />
</bean>
[...]
Это привело к следующей цепочке фильтров:
Security filter chain: [
SecurityContextPersistenceFilter
WebAsyncManagerIntegrationFilter
OAuth2AuthenticationProcessingFilter
SecurityContextHolderAwareRequestFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
LogoutFilter
]
Когда я сейчас настраиваю сервер ресурсов, добавив обработчик успеха выхода из системы, этоway:
@Override
public void configure( HttpSecurity http ) throws Exception
{
http.regexMatcher( "/oauth/(users|clients)/.*" )
.anonymous( ).disable( ).authorizeRequests( )
.regexMatchers( HttpMethod.POST, "/oauth/users/revoke" )
.access( "#oauth2.clientHasRole('ROLE_CLIENT') and (hasRole('ROLE_USER') or #oauth2.isClient())" )
.antMatchers( "/**" ).denyAll( )
.and( ).sessionManagement( ).sessionCreationPolicy( SessionCreationPolicy.STATELESS )
.and( ).csrf( ).disable( ).exceptionHandling( )
.accessDeniedHandler( this.oAuth2AccessDeniedHandler )
.defaultAuthenticationEntryPointFor( this.oauthAuthenticationEntryPoint,new AntPathRequestMatcher( "/**" ) )
.and( ).logout( ).logoutUrl( "/oauth/users/revoke" ).logoutSuccessHandler( revokeSuccessHandler( ) );
}
Обработчик выхода из системы запускается до применения OAuth2AuthenticationProcessingFilter и, следовательно, аутентификация не выполнялась.Цепочка фильтров выглядит следующим образом:
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
OAuth2AuthenticationProcessingFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
Объект аутентификации в обработчике успеха выхода из системы равен нулю, а логика в обработчике (с некоторыми дополнительными проверками на основе данного объекта аутентификации) больше не работает.Если я удаляю обработчик успеха выхода из системы, проверки OAuth2AuthenticationProcessingFilter выполняются правильно, и аутентификация работает как задумано (но тогда, конечно, выход из системы отсутствует).Если я изменю логику в обработчике выхода из системы и уберу токен из заголовка авторизации запроса, я мог бы загрузить авторизацию из хранилища токенов, а затем снова выполнить проверки доступа вручную, но, похоже, это не так.должно быть сделано ...
Итак, главная проблема в том, что LogoutFilter установлен перед OAuth2AuthenticationProcessingFilter в цепочке фильтров, и я не смог найти способ изменить порядок.Я попытался установить для свойства security.oauth2.resource.filter-order
значение 3, но это не помогло.Я также пробовал разные значения для аннотации @Order
, но безуспешно.Я полагаю, что можно пойти путем добавления пользовательского фильтра типа LogoutFilter после OAuth2AuthenticationProcessingFilter (или «до последнего», как это было сделано в конфигурации xml), выполнив что-то вроде and( ).addFilterAfter( revokeFilterBean(), OAuth2AuthenticationProcessingFilter.class )
Но я не могу создать экземпляр необходимогоКласс LogoutFilter, так как ему нужен список LogoutHandlers в качестве аргумента конструктора, которого у меня нет (передача нулевого значения приводит к ошибке и попытка автопроводки тоже не сработает).
Итак, как правильно?добиться правильного порядка фильтра?