2013-10-14 3 views
11

У меня возникли некоторые вопросы, получать мое приложение настроено с помощью аннотаций уровня метод контролируемой @EnableGlobalMethodSecurity Я использую инициализацию сервлета 3,0 стиля с использованиемМетод безопасность аннотации с конфигурацией Java и Spring Security 3.2

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { 

    public SecurityWebApplicationInitializer() { 
     super(MultiSecurityConfig.class); 
    } 
} 

Я попытался 2 различных способы инициализации AuthenticationManager как с собственными проблемами. Обратите внимание, что не с использованием @EnableGlobalMethodSecurity приводит к успешному запуску сервера, и вся защита формы выполняется, как ожидалось. Мои проблемы возникают, когда я добавляю @EnableGlobalMethodSecurity и @PreAuthorize("hasRole('ROLE_USER')") аннотации на мой контроллер.

Я пытаюсь самостоятельно настроить защиту на основе форм и api. Аннотации, основанные на методе, должны работать только для защиты api.

Одна конфигурация была следующей.

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled=true) 
public class MultiSecurityConfig { 

    @Configuration 
    @Order(1) 
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 
     protected void configure(HttpSecurity http) throws Exception { 
      http.antMatcher("/api/**").httpBasic(); 
     } 

     protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception { 
      auth.inMemoryAuthentication() 
       .withUser("user").password("password").roles("USER").and() 
       .withUser("admin").password("password").roles("USER", "ADMIN"); 
     } 
    } 

    @Configuration 
    public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { 
     public void configure(WebSecurity web) throws Exception { 
      web.ignoring().antMatchers("/static/**","/status"); 
     } 

     protected void configure(HttpSecurity http) throws Exception { 
      http.authorizeRequests().anyRequest().hasRole("USER").and() 
       .formLogin().loginPage("/login").permitAll(); 
     } 

     protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception { 
      auth.inMemoryAuthentication() 
       .withUser("user").password("password").roles("USER").and() 
       .withUser("admin").password("password").roles("USER", "ADMIN"); 
     } 
    } 

} 

Это не идеально, как я действительно хочу только одну регистрацию механизма аутентификации, но главный вопрос в том, что это приводит к следующим исключением:

java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found [] 

Насколько мне известно @EnableGlobalMethodSecurity устанавливает свой собственный AuthenticationManager, поэтому я не уверен, в чем проблема.

Вторая конфигурация следующая.

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled=true) 
public class MultiSecurityConfig { 

    @Bean 
    protected AuthenticationManager authenticationManager() throws Exception { 
     return new AuthenticationManagerBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR) 
       .inMemoryAuthentication() 
        .withUser("user").password("password").roles("USER").and() 
        .withUser("admin").password("password").roles("USER", "ADMIN").and() 
        .and() 
       .build(); 
    } 

    @Configuration 
    @Order(1) 
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 
     @Override protected void configure(HttpSecurity http) throws Exception { 
      http.antMatcher("/api/**").httpBasic(); 
     } 
    } 

    @Configuration 
    public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { 
     public void configure(WebSecurity web) throws Exception { 
      web.ignoring().antMatchers("/static/**","/status"); 
     } 

     protected void configure(HttpSecurity http) throws Exception { 
      http.authorizeRequests().anyRequest().hasRole("USER").and() 
       .formLogin().loginPage("/login").permitAll(); 
     } 
    } 

} 

Эта конфигурация фактически начинается успешно, но с исключением

java.lang.IllegalArgumentException: A parent AuthenticationManager or a list of AuthenticationProviders is required 
at org.springframework.security.authentication.ProviderManager.checkState(ProviderManager.java:117) 
at org.springframework.security.authentication.ProviderManager.<init>(ProviderManager.java:106) 
at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.performBuild(AuthenticationManagerBuilder.java:221) 

и когда я проверяю я обнаружил, что безопасность не работает.

Я смотрел на это уже пару дней и даже после погружения в код обеспечения безопасности весны, я не могу найти, что не так с моей конфигурацией.

Я использую spring-security-3.2.0.RC1 и spring-framework-3.2.3.RELEASE.

+0

Где и как вы загружаете этот «MultiSecurityConfig». Загружается ли это 'ContextLoaderListener'? Если такая защита не будет работать, так как ваши 'Controllers' обрабатываются вашим' DispatcherServlet'. –

ответ

12

Когда вы используете методы protected registerAuthentication на WebSecurityConfigurerAdapter, он просматривает Аутентификацию на WebSecurityConfigurerAdapter, так что EnableGlobalMethodSecurity не может найти его. Если вы думаете об этом ... это имеет смысл, поскольку метод защищен.

Ошибка, которую вы видите, на самом деле является отладчиком (обратите внимание, что уровень DEBUG). Причина в том, что Spring Security попробует несколько разных способов автоматического подключения глобальной безопасности методов. В частности EnableGlobalMethodSecurity будет попробовать следующие способы, чтобы попытаться получить AuthenticationManager:

  • Если продлить GlobalMethodSecurityConfiguration и переопределить registerAuthentication он будет использовать AuthenticationManagerBuilder, который был принят в.Это позволяет изолировать AuthenticationManager так же, как вы можете сделать это с помощью WebSecurityConfigurerAdapter
  • Попробуйте построить из общего общего экземпляра AuthenticationManagerBuilder, если он сбой, он регистрирует сообщение об ошибке, которое вы видите (обратите внимание, что в журналах также указано «Это ok на данный момент, мы попытаемся напрямую использовать AuthenticationManager »)
  • Попробуйте использовать AuthenticationManager, который отображается как компонент.

Для вашего кода, вы собираетесь быть лучше с помощью что-то вроде следующего:

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled=true) 
public class MultiSecurityConfig { 
    // Since MultiSecurityConfig does not extend GlobalMethodSecurityConfiguration and 
    // define an AuthenticationManager, it will try using the globally defined 
    // AuthenticationManagerBuilder to create one 

    // The @Enable*Security annotations create a global AuthenticationManagerBuilder 
    // that can optionally be used for creating an AuthenticationManager that is shared 
    // The key to using it is to use the @Autowired annotation 
    @Autowired 
    public void registerSharedAuthentication(AuthenticationManagerBuilder auth) throws Exception { 
     auth 
      .inMemoryAuthentication() 
       .withUser("user").password("password").roles("USER").and() 
       .withUser("admin").password("password").roles("USER", "ADMIN"); 
    } 

    @Configuration 
    @Order(1) 
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { 
     // Since we didn't specify an AuthenticationManager for this class, 
     // the global instance is used 


     protected void configure(HttpSecurity http) throws Exception { 
      http 
       .antMatcher("/api/**") 
       .httpBasic(); 
     } 
    } 

    @Configuration 
    public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { 
     // Since we didn't specify an AuthenticationManager for this class, 
     // the global instance is used 

     public void configure(WebSecurity web) throws Exception { 
      web 
       .ignoring() 
        .antMatchers("/static/**","/status"); 
     } 

     protected void configure(HttpSecurity http) throws Exception { 
      http 
       .authorizeRequests() 
        .anyRequest().hasRole("USER") 
        .and() 
       .formLogin() 
        .loginPage("/login") 
        .permitAll(); 
     } 
    } 

} 

Примечание: Более подробную документацию вокруг этого будет добавляться в ссылке в ближайшие дни.

+0

Спасибо, Роб, похоже, что большая часть моей проблемы дошла до моего понимания (или неправильного понимания) области при использовании конфигурации кода. Это делает вещи намного яснее. – Luke

+1

Следующий вопрос. Защита уровня метода по-прежнему не срабатывает при этой конфигурации. Я аннотировал мой класс, чтобы требовать роль ADMIN, однако аутентифицированный USER успешно выполняет этот метод. Это заставляет меня думать, что аутентификация работает правильно, а авторизация - нет. Есть предположения? – Luke

+0

Я только что загрузил класс, создав компонент в этой конфигурации, и он распознает и исполняет все аннотации. У меня явно есть кое-что, что нужно делать вокруг контекста и области, используя конфигурацию кода! – Luke

Смежные вопросы