甚至没有调用自定义 Spring Security 身份验证提供程序?

Posted

技术标签:

【中文标题】甚至没有调用自定义 Spring Security 身份验证提供程序?【英文标题】:Custom Spring Security Authentication provider not even being called? 【发布时间】:2021-12-25 19:04:32 【问题描述】:

我需要从 3rd 方应用授权用户。基本上这是一个 REST api 调用,但这不是问题。每次我导航到一个页面时,我都会自动重定向到错误页面,根本没有任何解释。日志中没有任何内容,即使我的日志记录:logging.level.org.springframework.security=DEBUG 和我的根级别为 WARN

我的安全配置如下所示:

@Configuration
@EnableWebSecurity
@ConfigurationProperties("security")
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter 

  @Autowired
  ELPAuthenticationProvider authenticationProvider;

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

  @Override
  protected void configure(HttpSecurity http) throws Exception 
    elpLogger.debug("****************Configuring HttpSecurity");
    http.authorizeRequests().antMatchers("/hello/**").permitAll();
    http.authorizeRequests().anyRequest().authenticated();
  


还有我的身份验证提供者:

@Component
public class ELPAuthenticationProvider implements AuthenticationProvider 

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException 
    logger.debug("In Authenticate");
    final List<GrantedAuthority> grantedAuths = new ArrayList<>();
    grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
    final UserBean principal = new UserBean("admin", "password", grantedAuths);
    final Authentication auth = new UsernamePasswordAuthenticationToken(principal, "password", grantedAuths);
    return auth;
  

  @Override
  public boolean supports(Class<? extends Object> authentication) 
    return true;
  

对我来说,这看起来应该验证任何东西。但是除了我的 HelloWorldController ("/hello") 之外的所有东西我都会被扔到我的错误页面而没有任何解释。我的日志如下所示:

o.s.security.web.FilterChainProxy        : Securing GET /
s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to anonymous SecurityContext
o.s.s.w.a.i.FilterSecurityInterceptor    : Failed to authorize filter invocation [GET /] with attributes [authenticated]
o.s.s.w.s.HttpSessionRequestCache        : Saved request http://localhost:7080/ to session
o.s.s.w.a.Http403ForbiddenEntryPoint     : Pre-authenticated entry point called. Rejecting access
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
c.e.web.controllers.ELPErrorController   : ************************  Error handler

所以我不知道为什么我的身份验证提供程序甚至没有被调用,其次,我不知道为什么会抛出异常。 (或者为什么我被重定向到错误页面而不是未授权页面)

有什么想法吗?

编辑 我从 AuthenticationProvider 中删除了 @Component 注释,并在我的主 Application.java 中将其声明为 bean 将其自动连接到 SecurityConfiguration 中。我在上面的示例中进行了更改。完全相同的问题。没有变化。

【问题讨论】:

请 (1.) 还要确保 logging.level.&lt;package.of.elpauthenticationprovider&gt;=debug 和 (2.) 它是组件(自动扫描?)还是 bean? (我知道/理解它是完全一样的,但可能是冲突的......当一起使用时(没有警告??)) @xerx593 没有变化。日志级别是调试。但我确实有两个组件注释,并将其声明为 Bean。我去掉了组件注解,把Bean方法放到Application.java中我相应地调整了问题中的代码。 除了下面的@fast-reflexes 回答之外,请确保您不要两次致电http.authorizeRequests()。第二次调用会覆盖第一次。您可以将规则链接在一起,如:http.authorizeRequests().antMatchers("/hello/**").permitAll()..anyRequest().authenticated(). 【参考方案1】:

鉴于AuthenticationProvider 接口中的authenticate 方法将身份验证作为参数,我们可以放心,必须进行某种初始身份验证,以便为提供者提供一些工作。以下摘录在 Kotlin 中给出。

即使使用带有基本身份验证的标准设置

@Configuration
class SecurityAssets 

    @Bean
    fun passwordEncoder(): PasswordEncoder =
        return BCryptPasswordEncoder()

 

@EnableWebSecurity
class Config(val encoder: PasswordEncoder): WebSecurityConfigurerAdapter() 

    override fun configure(auth: AuthenticationManagerBuilder) 
        auth
            .inMemoryAuthentication()         
               .withUser("user")
               .password(encoder.encode("password"))
               .roles("USER")
    

    override fun configure(http: HttpSecurity) 
        http
            .authorizeRequests()
                .anyRequest()
                    .authenticated()
     

以上内容不会触发身份验证。为此,我们需要为 Spring 添加一些方法来创建初始身份验证,然后由配置的提供者进行身份验证:

@EnableWebSecurity
class Config(val encoder: PasswordEncoder): WebSecurityConfigurerAdapter() 

    ...

    override fun configure(http: HttpSecurity) 
        http
            .authorizeRequests()
                .anyRequest()
                    .authenticated()
                    .and()
                    .httpBasic()
     

现在可以了!

在你的情况下,类似的事情也会起作用:

class CustomAuthenticationProvider : AuthenticationProvider 

    override fun authenticate(authentication: Authentication): Authentication 
        println("In Authenticate")
        val grantedAuths: MutableList<GrantedAuthority> = ArrayList()
        grantedAuths.add(SimpleGrantedAuthority("ROLE_USER"))
        val principal = AuthenticatedPrincipal  "Name" 
        return UsernamePasswordAuthenticationToken(principal, "password", grantedAuths)
    

    override fun supports(authentication: Class<*>?): Boolean 
        println("In supports")
        return true
    


@EnableWebSecurity
class Config(val encoder: PasswordEncoder): WebSecurityConfigurerAdapter() 

    override fun configure(auth: AuthenticationManagerBuilder) 
        auth
            .authenticationProvider(CustomAuthenticationProvider())
    

    override fun configure(http: HttpSecurity) 
        http
            .authorizeRequests()
                .anyRequest()
                    .authenticated()
                    .and()
                    .httpBasic()
     

如何使自定义提供程序对配置器可用并不重要,您可以使用 bean 或简单地在需要时将其实例化。

如果您需要一些不同的主要身份验证方法,您可以将httpBasic 更改为其他内容。如果您需要自定义实际的身份验证方法(例如,查找一些自定义标头或其他过滤器尚不存在的东西),那么您应该实现一个自定义过滤器,该过滤器被添加到安全过滤器链中,然后委托给您的提供商。

安全过滤器链中的过滤器是实际处理请求的内容,简单地添加安全提供程序不会添加新过滤器,在本例中,httpBasic 会添加新过滤器。

【讨论】:

以上是关于甚至没有调用自定义 Spring Security 身份验证提供程序?的主要内容,如果未能解决你的问题,请参考以下文章

spring security 没有调用 loadUserByUsername() 方法

无法在 Spring Boot Security 中登录到我的自定义登录页面

未调用 Spring Security 自定义登录表单

Spring-security/Grails 应用程序 - 未调用自定义 WebSecurity 配置

Spring Security自定义拦截器

Spring security - 未调用自定义 userDetailsS​​ervice 实现