问题 未调用自定义身份验证提供程序


我正在尝试使用Spring Security设置客户AuthenticationProvider,但没有太多运气让它运行起来。我在用着 Java配置 所以我可能会遗漏一些简单的东西,但由于大多数学习材料都是基于XML配置的,所以它并没有向我发出。

这是使用Spring v4.0.1.RELEASE但使用Spring Security v3.2.2.RELEASE。也许版本号冲突?

据我所知,我所要做的就是创建我的提供者:

public class KBServicesAuthProvider implements AuthenticationProvider {
  @Autowired
  private ApplicationConfig applicationConfig;

  @Autowired
  private SessionServiceClient sessionServiceClient;

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String email = (String) authentication.getPrincipal();
    String password = (String) authentication.getCredentials();

    try {
      KBSessionInfo sessionInfo = sessionServiceClient.login(applicationConfig.getKbServicesPresenceId(), email,
          password);

      List<GrantedAuthority> grantedRoles = new ArrayList<>();
      for (KBRoleMembership role : sessionInfo.getAuthenticatedUser().getRoleMemberships()) {
        grantedRoles.add(new SimpleGrantedAuthority(role.getRoleId()));
      }

      return new UsernamePasswordAuthenticationToken(email, password, grantedRoles);
    } catch (InvalidSessionException e) {
      throw new AuthenticationCredentialsNotFoundException("Username or password was not accepted", e);
    }
  }

  @Override
  public boolean supports(Class<?> authentication) {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
  }
}

然后设置一个类来描述我的安全设置。此类链接在我的提供者中:

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired(required = true)
  SessionServiceClient sessionServiceClient;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/").permitAll().anyRequest().authenticated();
    http.formLogin().loginPage("/login").permitAll().and().logout().permitAll();
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(getKBServicesAuthenticationProvider());
  }

  @Bean
  protected AuthenticationProvider getKBServicesAuthenticationProvider() {
    return new KBServicesAuthProvider();
  }
}

但我没有在日志中看到任何内容,我的调试点都没有被击中。该应用程序的行为是不安全的(所以我仍然可以访问各种URL等)。

关于我应该检查什么的任何想法?


11500
2018-03-17 11:51


起源



答案:


这可能不是完整的答案,因为我自己也在努力解决这个问题。我正在使用自定义身份验证提供程序和自定义用户详细信息服务。我看到了与您相同的行为 - 断点在我的用户详细信息服务中被点击,但在我的身份验证提供程序中没有。这是我的整个配置类的样子:

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;
    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        AuthenticationProvider rememberMeAuthenticationProvider = rememberMeAuthenticationProvider();
        TokenBasedRememberMeServices tokenBasedRememberMeServices = tokenBasedRememberMeServices();

        List<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>(2);
        authenticationProviders.add(rememberMeAuthenticationProvider);
        authenticationProviders.add(customAuthenticationProvider);
        AuthenticationManager authenticationManager = authenticationManager(authenticationProviders);

        http
                .csrf().disable()
                .headers().disable()
                .addFilter(new RememberMeAuthenticationFilter(authenticationManager, tokenBasedRememberMeServices))
                .rememberMe().rememberMeServices(tokenBasedRememberMeServices)
                .and()
                .authorizeRequests()
                .antMatchers("/js/**", "/css/**", "/img/**", "/login", "/processLogin").permitAll()
                .antMatchers("/index.jsp", "/index.html", "/index").hasRole("USER")
                .antMatchers("/admin", "/admin.html", "/admin.jsp", "/js/saic/jswe/admin/**").hasRole("ADMIN")
                .and()
                .formLogin().loginProcessingUrl("/processLogin").loginPage("/login").usernameParameter("username").passwordParameter("password").permitAll()
                .and()
                .exceptionHandling().accessDeniedPage("/login")
                .and()
                .logout().permitAll();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**", "/img/**");
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationManager authenticationManager(List<AuthenticationProvider> authenticationProviders) {
        return new ProviderManager(authenticationProviders);
    }

    @Bean
    public TokenBasedRememberMeServices tokenBasedRememberMeServices() {
        return new TokenBasedRememberMeServices("testKey", userDetailsService);
    }

    @Bean
    public AuthenticationProvider rememberMeAuthenticationProvider() {
        return new org.springframework.security.authentication.RememberMeAuthenticationProvider("testKey");
    }

    protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }
}

我刚刚发现,如果我专门将我的身份验证提供程序添加到HttpSecurity对象,我的断点开始受到攻击:

http
                .csrf().disable()
                .headers().disable()
                .authenticationProvider(customAuthenticationProvider)

我的目标是让BCryptPasswordEncoder工作,而不是这个配置 - 一切都返回为坏凭据。无论如何,只是想我会分享。


6
2018-03-17 19:07



总是很高兴知道你不是唯一一个苦苦挣扎的人!当我明天回到工作岗位时,我会放手一搏,让你知道如果我取得进步 - Lee Theobald
我希望它能帮到你。这让我的密码编码器也能正常工作,但是现在我觉得我破坏了我的rememberMe服务! - Bal
仍然没有这个工作,但至少你给了我一个完整的例子来! - Lee Theobald


答案:


这可能不是完整的答案,因为我自己也在努力解决这个问题。我正在使用自定义身份验证提供程序和自定义用户详细信息服务。我看到了与您相同的行为 - 断点在我的用户详细信息服务中被点击,但在我的身份验证提供程序中没有。这是我的整个配置类的样子:

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;
    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        AuthenticationProvider rememberMeAuthenticationProvider = rememberMeAuthenticationProvider();
        TokenBasedRememberMeServices tokenBasedRememberMeServices = tokenBasedRememberMeServices();

        List<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>(2);
        authenticationProviders.add(rememberMeAuthenticationProvider);
        authenticationProviders.add(customAuthenticationProvider);
        AuthenticationManager authenticationManager = authenticationManager(authenticationProviders);

        http
                .csrf().disable()
                .headers().disable()
                .addFilter(new RememberMeAuthenticationFilter(authenticationManager, tokenBasedRememberMeServices))
                .rememberMe().rememberMeServices(tokenBasedRememberMeServices)
                .and()
                .authorizeRequests()
                .antMatchers("/js/**", "/css/**", "/img/**", "/login", "/processLogin").permitAll()
                .antMatchers("/index.jsp", "/index.html", "/index").hasRole("USER")
                .antMatchers("/admin", "/admin.html", "/admin.jsp", "/js/saic/jswe/admin/**").hasRole("ADMIN")
                .and()
                .formLogin().loginProcessingUrl("/processLogin").loginPage("/login").usernameParameter("username").passwordParameter("password").permitAll()
                .and()
                .exceptionHandling().accessDeniedPage("/login")
                .and()
                .logout().permitAll();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**", "/css/**", "/img/**");
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationManager authenticationManager(List<AuthenticationProvider> authenticationProviders) {
        return new ProviderManager(authenticationProviders);
    }

    @Bean
    public TokenBasedRememberMeServices tokenBasedRememberMeServices() {
        return new TokenBasedRememberMeServices("testKey", userDetailsService);
    }

    @Bean
    public AuthenticationProvider rememberMeAuthenticationProvider() {
        return new org.springframework.security.authentication.RememberMeAuthenticationProvider("testKey");
    }

    protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }
}

我刚刚发现,如果我专门将我的身份验证提供程序添加到HttpSecurity对象,我的断点开始受到攻击:

http
                .csrf().disable()
                .headers().disable()
                .authenticationProvider(customAuthenticationProvider)

我的目标是让BCryptPasswordEncoder工作,而不是这个配置 - 一切都返回为坏凭据。无论如何,只是想我会分享。


6
2018-03-17 19:07



总是很高兴知道你不是唯一一个苦苦挣扎的人!当我明天回到工作岗位时,我会放手一搏,让你知道如果我取得进步 - Lee Theobald
我希望它能帮到你。这让我的密码编码器也能正常工作,但是现在我觉得我破坏了我的rememberMe服务! - Bal
仍然没有这个工作,但至少你给了我一个完整的例子来! - Lee Theobald


你忘记了 @Autowired 注解。

@Autowired
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  auth.authenticationProvider(getKBServicesAuthenticationProvider());
}

此外,您可能想要删除 .antMatchers("/").permitAll()

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests().anyRequest().authenticated();
  http.formLogin().loginPage("/login").permitAll().and().logout().permitAll();
}

3
2018-03-17 14:52



我添加了@AutoWired注释,但仍然没有运气。无论是否有注释,configure方法都会被调用,因此会发生一些事情。但我设置的身份验证提供程序从未调用任何方法。 - Lee Theobald
你也删除了 .antMatchers("/").permitAll()? - ChristopherZ


我有同样的问题(我的自定义身份验证提供程序没有被点击)并通过介绍解决了这个问题 springSecurityFilterChain, 看完之后 为什么Spring Security在Tomcat中工作,但在部署到Weblogic时却没有? 所以我的问题可能与WebServer特别有关,但我在Tomcat上也有自定义身份验证提供程序问题,并检查我的配置现在可以在Tomcat上运行。

我正在使用spring boot 1.4.1版本,其中包含Spring 4.3.3和Spring Security 4.1.3及以下版本 传统部署

我测试了我的配置 Tomcat v9.0 并且 WebLogic 12c R2 并检查它是否适用于两者。 希望这对至少使用Tomcat的人有帮助。

以下是我从主类开始的配置。

Application.java

public class Application {
    public static void main( String[] args ) {
        SpringApplication.run(new Class[] {AppConfig.class, Initializer.class, SecurityInitializer.class}, args);
    }
}

Initializer.java

public class Initializer extends SpringBootServletInitializer implements WebApplicationInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(AppConfig.class);
    }

    @Override
    public void onStartup(ServletContext container) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(AppConfig.class);

        // Manage the lifecycle of the root application context
        container.addListener(new ContextLoaderListener(rootContext));

        // Create the dispatcher servlet's Spring application context
        AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
        dispatcherContext.register(WebConfig.class);

        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher = container.addServlet("my-servlet", new DispatcherServlet(dispatcherContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/*");
    }
}

这里AbstractSecurityWebApplicationInitializer正在构建 springSecurityFilterChain 来自onStartup方法。我没有实现任何,因为我正在尝试使用默认配置。

SecurityInitializer.java

public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {

}

AppConfig.java

@Configuration
@EnableAutoConfiguration
@EnableScheduling
@EnableMBeanExport
@EnableAsync
@EnableAspectJAutoProxy
@ComponentScan("com.my.package")
public class AppConfig {


}

SecurityConfig.java

@Configuration
@EnableWebSecurity
@ComponentScan("com.my.package")
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private RestfulRemoteAuthenticationProvider restfulRemoteAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(restfulRemoteAuthenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }
}

WebConfig.java

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.my.controller.package")
public class WebConfig extends WebMvcConfigurerAdapter {

    @Bean
    public InternalResourceViewResolver internalViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/jsp/");
        viewResolver.setSuffix(".jsp");
        viewResolver.setOrder(1);
        return viewResolver;
    }
}

这是我的自定义身份验证提供程序,通过Restful请求从其他组件获取身份验证信息

RestfulRemoteAuthenticationProvider.java 

@Component
public class RestfulRemoteAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private ManagementClientAdapterFactory managementClientAdapterFactory;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        // my logic to get and configure authSource which is my environment specific thing, also same for RemoteAuthRequestResult

        RemoteAuthRequestResult result = (RemoteAuthRequestResult)authSource.sendRequest();
        if(result.isAuthenticated()) {
            List<GrantedAuthority> grantedAuths = new ArrayList<>();
            grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
            return new UsernamePasswordAuthenticationToken(username, password, grantedAuths);
        }
        throw new BadCredentialsException("User not found by given credential");
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

2
2017-10-11 17:17





我遇到了同样的问题,问题在于你的方法总会返回false。

@Override
public boolean supports(Class<?> authentication) {
      return authentication.equals
  (UsernamePasswordAuthenticationToken.class);
}

将上述方法更改为以下方法,问题将得到解决。

@Override
    public boolean supports(Class<?> authentication) {
          return (UsernamePasswordAuthenticationToken.class
                    .isAssignableFrom(authentication));
    }

2
2018-06-20 10:13





   Something like should be present in java config 
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class HelloMethodSecurityConfig {
}

1
2018-03-17 14:41





@EnableWebMvcSecurity 将在4.0中弃用 https://jira.spring.io/browse/SEC-2790

您可能需要重新考虑配置。


1
2017-07-10 09:06





<security:global-method-security pre-post-annotations="enabled"/>

0
2018-03-17 12:52



我没有使用XML配置,而是使用Java配置。我会看看是否有替代方案。 - Lee Theobald
@EnableGlobalMethodSecurity(prePostEnabled = true)虽然我不认为这会解决你的问题。 - Bal