Иногда бывает необходимость настроить разные SecurityFilterChain для разных разделов сайта или для разных REST-сервисов. Это, на самом деле, довольно просто.
Как работают несколько SecurityFilterChain в одном приложении описано в документации по Spring Security.
В случае с XML-конфигурацией нам нужно сделать два блока <security:http:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<security:http pattern="/site/*" security="none" /> <security:http pattern="/rest/**" realm="SecRemoting" create-session="always" authentication-manager-ref="authenticationManager" entry-point-ref="authenticationEntryPoint" security-context-repository-ref="securityContextRepository"> <!-- <security:http-basic /> --> <security:custom-filter ref="customSecurityFilter" after = "BASIC_AUTH_FILTER" /> <security:intercept-url pattern="/rest/v1/PublicService/**" access="permitAll" /> <security:intercept-url pattern="/rest/v1/UserService/login" access="permitAll" /> <security:intercept-url pattern="/rest/**" access="hasRole('ROLE_USER')" /> <!-- Default to Spring MVC's CORS configuration --> <security:cors /> <security:csrf disabled="true"/> </security:http> |
Обратите внимание на атрибут pattern у http. Именно по нему определяется, какой из SecurityFilterChain-ов отработает.
В примере выше для адресов /site/home, /site/about и прочих, начинающихся на /site/, никакой аутентификации не будет. Они будут доступны всем. А для адресов /rest/v1/UserService, /rest/v1/SomeService, /rest/StrangeService и прочих, начинающихся с /rest/ нужна будет иметь роль ROLE_USER, кроме адресов, начинающихся с /rest/v1/PublicService, и адреса /rest/v1/UserService/login.
Как же перевести это в Java-конфигурацию, которая обычно и используется со Spring Boot? Нам просто нужно объявить два бина SecurityFilterChain:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
@Bean public SecurityFilterChain securityFilterChainAll(HttpSecurity http) throws Exception { return http .securityMatcher("/styles/**", "/images/**", "/site**") .authorizeHttpRequests((authorize) -> authorize.requestMatchers("/styles/**").permitAll() .requestMatchers("/images/**").permitAll() .requestMatchers("/site/**").permitAll() ) .build(); } @Bean public SecurityFilterChain securityFilterChain1(HttpSecurity http, AuthenticationManager authenticationManager, SecurityContextRepository securityContextRepository ) throws Exception { http .securityMatcher("/rest/**") .csrf(AbstractHttpConfigurer::disable) .addFilterAfter(new CustomAuthenticationProcessingFilter( authenticationManager, securityContextRepository), BasicAuthenticationFilter.class) .authorizeHttpRequests((authorize) -> authorize.requestMatchers("/rest/v1/PublicService/**").permitAll() .requestMatchers("/rest/v1/UserService/login").permitAll() .requestMatchers("/rest/**").hasRole("USER") ) .securityContext((securityContext) -> securityContext .securityContextRepository(securityContextRepository) ) .authenticationManager(authenticationManager) .sessionManagement((session) -> session .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) ); return http.build(); } |
Выглядит это всё, конечно, немного иначе. Я довольно долго переделывал XML-конфигурацию в Java-конфигурацию для своей будущей книги, но на самом деле идея там та же самая. Мы просто определяем два SecurityFilterChain, а разделяются они по шаблону в securityMatcher (аналог pattern для XML-конфигурации).
Довольно короткая статья получилась, но я не знаю, что ещё тут можно расписать, кроме этих примеров.