Spring Security 多个成功的身份验证提供程序

Posted

技术标签:

【中文标题】Spring Security 多个成功的身份验证提供程序【英文标题】:Spring Security multiple successful authentication providers 【发布时间】:2018-05-07 18:52:04 【问题描述】:

我希望我的 Web 应用程序的用户通过 LDAP 和其他自定义身份验证进行身份验证。这是一个用 Kotlin 编写的 Spring Boot 应用程序。我已将 AuthenticationManagerBuilder 配置如下

@Autowired
lateinit var authenticationProvider: CustomAuthenticationProvider

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

    auth
            .ldapAuthentication()
                .userDnPatterns("uid=0,ou=people")
                .groupSearchBase("ou=groups")
                .contextSource()
                .url("ldap://localhost:8389/dc=example,dc=com")
            .and()
                .passwordCompare()
                .passwordEncoder(PlaintextPasswordEncoder())
                .passwordAttribute("userPassword")

我想链接身份验证,以便如果 CustomAuthenticationProvider 成功进行身份验证(函数身份验证不抛出),身份验证继续使用 LDAP 身份验证提供程序。

如果 CustomAuthenticationProvider 成功通过身份验证,则不会评估 LDAP 身份验证(以及任何后续身份验证提供程序)。仅当 CustomAuthenticationProvider 抛出时,才会执行 LDAP 身份验证。

我已经阅读了许多文章(例如 Multiple Authentication Providers in Spring Security),其中详细说明了具有多个身份验证提供程序但具有 OR 行为而不是 AND 行为。有什么建议吗?

【问题讨论】:

这怎么可能?如果您的身份验证提供程序公开身份验证,为什么要 LDAP 进行身份验证,您已经通过身份验证。唯一的方法是,您的身份验证提供程序不会公开身份验证。所以你还没有通过身份验证。 【参考方案1】:

也许我有一些。但是让我们分析一下之前的幕后情况。

Spring Security (ProviderManager) 中的默认身份验证管理器实现维护一个身份验证提供者列表,第一个执行成功身份验证的提供者会停止链 - 其余的不会被调用。我相信你无法改变这一点。当您使用AuthenticationManagerBuilder 时,您会在ProviderManager 中添加身份验证提供程序。

下图显示了正在发生的事情的高级概述:

在源代码中是这样的(为简洁起见,细节略过):

public Authentication authenticate(Authentication authentication)
            throws AuthenticationException 
        Class<? extends Authentication> toTest = authentication.getClass();
        ...
        for (AuthenticationProvider provider : getProviders()) 
            if (!provider.supports(toTest)) 
                continue;
            

            try 
                result = provider.authenticate(authentication);

                if (result != null) 
          ...
                    break;
                
            
      ...
            catch (AuthenticationException e) 
                lastException = e;
            
        

        if (result != null) 
            ...
            return result;
        
  

那你能做什么……嗯。首先,@dur 的问题是有效的 :-) 其次 - 很明显,您无法使用对我有意义的标准身份验证管理器来做您想做的事情。

我认为如果你仍然想走那条路,你可以尝试两件事:

    在您的过滤器链中提供您自己的身份验证管理器实现。这对我来说似乎有点挑战。 确保您的自定义身份验证提供程序处理所有必要的身份验证操作。

【讨论】:

老兄!看java if (result != null) // ... ... break; 你已经猜到了!成功返回null,它会处理下一个!异常会破坏 for 循环。所以,为下一个返回 null,为拒绝而抛出!

以上是关于Spring Security 多个成功的身份验证提供程序的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security - 多个身份验证提供程序

特定 url 的多个身份验证提供程序 - Spring Boot Security

Spring Security:针对多个 LDAP 服务器和基于 DAO 的身份验证进行身份验证

Spring security - 身份验证后的 GWT 重定向

Spring Security 预认证账户锁定检查

防止 Spring Security 通过下一个身份验证提供程序对具有 BadCredentialException 的用户进行身份验证