首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Spring Security Java -发现多个Authentication Manager -2 bean错误

Spring Security Java -发现多个Authentication Manager -2 bean错误
EN

Stack Overflow用户
提问于 2015-08-20 05:19:23
回答 3查看 22K关注 0票数 10

我的应用程序中有两个身份验证管理器。

代码语言:javascript
复制
@Configuration
@EnableWebMvcSecurity
@ComponentScan
@ImportResource("classpath:security-context.xml")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private AuthenticationEntryPoint webAuthenticationEntryPoint = null;

    private AuthenticationManager webAuthenticationManager = null;

    private final webPreAuthenticatedProcessingFilter webPreAuthenticatedProcessingFilter;


    public WebSecurityConfig() {
        super();
        webPreAuthenticatedProcessingFilter = new webPreAuthenticatedProcessingFilter();
        webPreAuthenticatedProcessingFilter.setAuthenticationManager(webAuthenticationManager);
        webPreAuthenticatedProcessingFilter.setInvalidateSessionOnPrincipalChange(true);
        webPreAuthenticatedProcessingFilter.setContinueFilterChainOnUnsuccessfulAuthentication(Boolean.FALSE);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
            .antMatchers("/login", "/logoffUser", "/sessionExpired", "/error").permitAll()
            .anyRequest().authenticated().and().rememberMe().and().httpBasic()
            .authenticationEntryPoint(webAuthenticationEntryPoint).and()
            .addFilterAfter(webPreAuthenticatedProcessingFilter, webPreAuthenticatedProcessingFilter.class).csrf()
            .disable().logout().deleteCookies("JSESSIONID").logoutSuccessUrl("/logoff").invalidateHttpSession(true);
    }

    @Autowired
    @Qualifier("webAuthManager")
    public void setwebAuthenticationManager(AuthenticationManager webAuthenticationManager) {

        this.webAuthenticationManager = webAuthenticationManager;
        webPreAuthenticatedProcessingFilter.setAuthenticationManager(this.webAuthenticationManager);
    }

    @Autowired
    public void setwebAuthenticationEntryPoint(AuthenticationEntryPoint webAuthenticationEntryPoint) {

        this.webAuthenticationEntryPoint = webAuthenticationEntryPoint;
    }

}

PreAuthenticatedFilter类,

代码语言:javascript
复制
@Component("preAuthenticatedFilter")
public class WebPreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {   
    @Override
    @Autowired
    @Qualifier("webAuthManager")
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }
}

WebAuthenticationManager类,

代码语言:javascript
复制
@Service
@ComponentScan
@Component("webAuthManager")
public class WebAuthenticationManager implements AuthenticationManager {


    @Override
    public Authentication authenticate(Authentication authentication) {

       // ...

    }
}

以及具有多个身份验证管理器的xml文件,

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security 
                        http://www.springframework.org/schema/security/spring-security-3.2.xsd">

    <bean id="ldapConfig" class="com.wellmanage.mnpi.core.jms.LdapConfig">
        <constructor-arg name="user" value="${ldap.conn.user}"/>
        <constructor-arg name="sid" value="${ldap.conn.sid}"/>
    </bean>

    <security:ldap-server url="${ldap.url}" 
        manager-dn="${ldap.conn.user}" manager-password="#{ldapConfig.getPassword()}" />

    <security:authentication-manager alias="ldapAuthManager" id="ldapAuthManager">
        <security:ldap-authentication-provider
            user-search-filter="(&amp;(sAMAccountName={0})(objectclass=organizationalPerson))"
            user-search-base="OU=${ldap.user-search-base.name}"
            group-search-filter="(member={0})" group-search-base="OU=Global-Groups"
            group-role-attribute="cn"/>
    </security:authentication-manager>

    <bean id="mq.accessDecisionManager"
        class="org.springframework.security.access.vote.AffirmativeBased">
        <constructor-arg>
            <list>
                <bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter"/>
            </list>
        </constructor-arg>
    </bean>
</beans>

即使我使用限定符,我也会得到下面的异常。

代码语言:javascript
复制
Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:133)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:474)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
    at com.wellmanage.mnpi.Application.main(Application.java:60)
Caused by: org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.initialize(TomcatEmbeddedServletContainer.java:98)
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.<init>(TomcatEmbeddedServletContainer.java:75)
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getTomcatEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:378)
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:155)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:157)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:130)
    ... 5 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found [webAuthManager, ldapAuthManager]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1119)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1014)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.boot.context.embedded.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:209)
    at org.springframework.boot.context.embedded.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:165)
    at org.springframework.boot.context.embedded.ServletContextInitializerBeans.addAsRegistrationBean(ServletContextInitializerBeans.java:160)
    at org.springframework.boot.context.embedded.ServletContextInitializerBeans.addAdaptableBeans(ServletContextInitializerBeans.java:143)
    at org.springframework.boot.context.embedded.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:74)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getServletContextInitializerBeans(EmbeddedWebApplicationContext.java:234)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.selfInitialize(EmbeddedWebApplicationContext.java:221)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.access$000(EmbeddedWebApplicationContext.java:84)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext$1.onStartup(EmbeddedWebApplicationContext.java:206)
    at org.springframework.boot.context.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:54)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5156)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found [webAuthManager, ldapAuthManager]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
    ... 26 more
Caused by: java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found [webAuthManager, ldapAuthManager]
    at org.springframework.util.Assert.isTrue(Assert.java:65)
    at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.lazyBean(AuthenticationConfiguration.java:112)
    at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.getAuthenticationMangerBean(AuthenticationConfiguration.java:122)
    at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.getAuthenticationManager(AuthenticationConfiguration.java:81)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.authenticationManager(WebSecurityConfigurerAdapter.java:236)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.getHttp(WebSecurityConfigurerAdapter.java:178)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:283)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:68)
    at com.wellmanage.mnpi.security.WebSecurityConfig$$EnhancerBySpringCGLIB$$c6c13351.init(<generated>)
    at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityBuilder.java:367)
    at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:320)
    at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:39)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:98)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$eb0d5df1.CGLIB$springSecurityFilterChain$3(<generated>)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$eb0d5df1$$FastClassBySpringCGLIB$$622492d6.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:309)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$eb0d5df1.springSecurityFilterChain(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
    ... 27 more
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-08-20 10:50:46

您需要设置2个提供程序,一个用于Ldap,另一个用于Web。AuthenticationManager (如果是ProviderManager实例)会选择相应的提供者进行身份验证。Manager主要管理实际工作的提供者列表。

就像(我猜在一个地方配置所有东西会更容易?):

代码语言:javascript
复制
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth  // you have to prepare following beans also
        .authenticationProvider(getLdapAuthenticationProvider())
        .authenticationProvider(getWebAuthenticationProvider());
}

请参阅http://docs.spring.io/spring-security/site/docs/4.0.2.RELEASE/reference/htmlsingle/#core-services-authentication-manager

票数 17
EN

Stack Overflow用户

发布于 2017-01-05 17:41:56

XML基础解决方案:如果您需要一个以上的身份验证管理器,那么您可以定义它,但是会得到警告"overriding registered authenticationmanager“,这意味着所有元素: HTTP都与最后定义的authenticationmanager匹配。

因此您可以针对所需XML库和安全v4.0+尝试此操作。

解决方案:您必须在authenticationmanager中使用" id“属性,并在"authentication-manager-ref”属性中使用在"HTTP“元素中定义相同id。因此安全机制会为特定HTTP请求获取适当的身份验证管理器。

示例代码:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">

<!--  HTTP basic authentication for Rest API when match url pattern="/api/**"    -->

<security:http realm="API" pattern="/api/**"
    use-expressions="true" auto-config="true" create-session="stateless"
    authentication-manager-ref="APIAuthenticationManager">

    <security:intercept-url pattern="/**" access="hasRole('USER')" />
    <security:http-basic />
    <security:csrf disabled="true" />
</security:http>

<security:authentication-manager id="APIAuthenticationManager"
    alias="APIAuthenticationManager">
    <security:authentication-provider user-service-ref="APIAuthenticationProvider" />
</security:authentication-manager> 

<bean class="com.example.security.api.APIAuthentication"
    id="APIAuthenticationProvider">
</bean>


<!-- From Login authentication for web portal when match url parrern ="/web/**"    -->


<security:http realm="WEB" auto-config="true"
    use-expressions="true" create-session="always"
    authentication-manager-ref="userAuthenticationManager">

    <security:intercept-url pattern="/resources/**" access="permitAll" />
    <security:intercept-url pattern="/web/login" access="hasRole('ROLE_ANONYMOUS')" />
    <security:intercept-url pattern="/web/dashboard**" access="hasRole('USER')" method="GET" />


    <!-- Set login, landing page, Successful, unsuccessful ... -->
    <security:form-login login-page="/web/login"
        default-target-url="/web/dashboard" 
        login-processing-url="/web/dashboard"
        always-use-default-target="true"

        authentication-failure-url="/web/login?error" 
        username-parameter="email"           
        password-parameter="encryptedPassword" />

    <!-- Set logout detail -->
    <security:logout logout-url="/web/logout"
        logout-success-url="/index.jsp" 
        delete-cookies="JSESSIONID"
        invalidate-session="true" />

    <security:csrf/>
</security:http>

<security:authentication-manager id="userAuthenticationManager" alias="userAuthenticationManager">
    <security:authentication-provider user-service-ref="userAuthenticationProvider" />
</security:authentication-manager>

<bean class="com.example.security.web.UserAuthentication"
    id="userAuthenticationProvider">

</bean>    

票数 2
EN

Stack Overflow用户

发布于 2021-06-30 00:53:49

公认的答案是正确的解决方案,但我认为理解AuthenticationManager如何从这个提供者列表中选择一个特定的AuthenticationProvider是很好的。在实现每个CustomAuthenticationProvider时,除了authenticate(Authentication auth)方法之外,还有一个带有签名boolean supports(Class<?> var1)的方法,我们必须实现该方法。对于AuthenticationManager中的每个提供程序,在调用provider.authenticate(authentication)方法之前,authenticationManager会通过调用此provider.support(authentication.getClass)来检查它是否支持当前的提供程序。由此,您可能会假设,support方法的实现如下所示

代码语言:javascript
复制
public boolean supports(Class<?> authentication) {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
}

请找到附件中突出显示的ProviderManager类源代码的屏幕截图,这是AuthenticationManager的默认实现。

You can find this is in the official source code too.

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32105846

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档