甚至没有调用自定义 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.<package.of.elpauthenticationprovider>=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 中登录到我的自定义登录页面