我们已经在spring security中使用单个Authentication Manager(LDAP)一段时间了,现在我们需要两个身份验证管理器,一个用于Login-LDAP,另一个用于基于IP的安全性。基于IP的安全性用作全局过滤器,LDAP仅用于登录。因此,两个身份验证管理器。 我们在类似的问题中尝试了解决方案,但仍面临同样的问题。
错误代码是:
org.springframework.beans.factory.BeanCreationException:错误 用名字创建bean ' org.springframework.security.filterChainProxy':init的调用 方法失败;嵌套异常是java.lang.IllegalArgumentException: 通用匹配模式(' / **')**在其他模式之前定义 在过滤器链中,导致它们被忽略。请检查 在命名空间或FilterChainProxy bean中排序 构造
Web.xml中
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/application-context.xml
/WEB-INF/spring/security-context.xml
</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher-servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/dispatcher-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher-servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Application Context.xml
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.8.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<tx:annotation-driven/>
<jdbc:embedded-database id="datasource" type="H2">
<jdbc:script location="classpath:init.sql"/>
</jdbc:embedded-database>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="datasource"/>
<property name="persistenceUnitName" value="autoservice"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<jpa:repositories base-package="com.oreilly.security.domain.repositories"/>
的security.xml
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<context:component-scan base-package="com.oreilly.security"/>
<bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />
<security:http use-expressions="false" authentication-manager-ref="LDAPAuth">
<security:form-login login-page="/login"
login-processing-url="/login" username-parameter="custom_username"
password-parameter="custom_password" default-target-url="/appointments/"
always-use-default-target="true" authentication-failure-url="/login?error=true" />
<security:logout logout-url="/logout"
logout-success-url="/login?logout=true" />
<security:intercept-url pattern="/appointments/*"
access="ROLE_USER,ROLE_ADMIN" />
<security:intercept-url pattern="/schedule/*"
access="ROLE_ADMIN" />
</security:http>
<security:http use-expressions="false" authentication-manager-ref="IpAuth">
<security:form-login login-page="/login"
login-processing-url="/login" username-parameter="custom_username"
password-parameter="custom_password" default-target-url="/appointments/"
always-use-default-target="true" authentication-failure-url="/login?error=true" />
<security:logout logout-url="/logout"
logout-success-url="/login?logout=true" />
<security:intercept-url pattern="/**"
access="ROLE_USER,ROLE_ADMIN" />
</security:http>
<security:authentication-manager id ="IpAuth">
<security:authentication-provider ref="customAuthenticationProvider"/>
</security:authentication-manager>
<security:authentication-manager id = "LDAPAuth">
<security:ldap-authentication-provider user-search-filter="(uid={0})"
group-search-base="ou=groups" group-search-filter="(uniqueMember={0})"
server-ref="ldapServer" user-context-mapper-ref="contextMapper" role-prefix="ROLE_"
group-role-attribute="cn"/>
</security:authentication-manager>
<security:ldap-server id="ldapServer" url="ldap://localhost:10389/dc=oreilly,dc=com"
manager-dn="uid=admin,ou=system" manager-password="secret"/>
</beans>
请让我们知道如何解决这个问题,已经被困住了几天: - )
答案 0 :(得分:0)
告诉您的是,您在security-config中有多个与http部分匹配的通用模式:
<security:http use-expressions="false" authentication-manager-ref="LDAPAuth">
<security:form-login login-page="/login"
login-processing-url="/login" username-parameter="custom_username"
password-parameter="custom_password" default-target-url="/appointments/"
always-use-default-target="true" authentication-failure-url="/login?error=true" />
<security:logout logout-url="/logout"
logout-success-url="/login?logout=true" />
<security:intercept-url pattern="/appointments/*"
access="ROLE_USER,ROLE_ADMIN" />
<security:intercept-url pattern="/schedule/*"
access="ROLE_ADMIN" />
</security:http>
<security:http use-expressions="false" authentication-manager-ref="IpAuth">
<security:form-login login-page="/login"
login-processing-url="/login" username-parameter="custom_username"
password-parameter="custom_password" default-target-url="/appointments/"
always-use-default-target="true" authentication-failure-url="/login?error=true" />
<security:logout logout-url="/logout"
logout-success-url="/login?logout=true" />
<security:intercept-url pattern="/**"
access="ROLE_USER,ROLE_ADMIN" />
</security:http>
如果您想拥有多个<security:http />
元素,则必须将模式应用于除最后一个元素之外的所有元素。例如:
<security:http pattern="/zone1/*" ... />
<security:http pattern="/zone2/*" ... />
...
<security:http ... /> <!-- the last one does not need to apply a pattern -->
根据您的配置,在您的第一个security:http
元素中,您有两种intercept-url
模式(/appointmens/**
,/schedule/**
)。您可以尝试将正则表达式匹配器应用于第一个security:http
元素(基于this答案):
<security:http request-matcher="regex" pattern="^/(appointments|schedule)(/(\S)+)+$"
use-expressions="false" authentication-manager-ref="LDAPAuth" >
...
</security:http>
<security:http use-expressions="false" authentication-manager-ref="IpAuth">
...
</security>
深入了解您的配置,我发现彼此之间的唯一区别是使用了不同的authentication-manager
。也许您可以尝试在同一个管理器中混合使用两个authentication-providers
,因为spring-security能够同时管理多个身份验证提供程序。它能够检查一个提供商的登录请求,然后检查另一个(或其他)的登录请求,然后采取相应的行动。
或多或少会像这样:
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<context:component-scan base-package="com.oreilly.security"/>
<bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />
<security:http use-expressions="false" authentication-manager-ref="authenticationManager">
<security:form-login login-page="/login"
login-processing-url="/login" username-parameter="custom_username"
password-parameter="custom_password" default-target-url="/appointments/"
always-use-default-target="true" authentication-failure-url="/login?error=true" />
<security:logout logout-url="/logout"
logout-success-url="/login?logout=true" />
<security:intercept-url pattern="/appointments/*"
access="ROLE_USER,ROLE_ADMIN" />
<security:intercept-url pattern="/schedule/*"
access="ROLE_ADMIN" />
<security:intercept-url pattern="/**"
access="ROLE_USER,ROLE_ADMIN" />
</security:http>
<security:authentication-manager id ="authenticationManager">
<security:authentication-provider ref="customAuthenticationProvider"/>
<security:ldap-authentication-provider user-search-filter="(uid={0})"
group-search-base="ou=groups" group-search-filter="(uniqueMember={0})"
server-ref="ldapServer" user-context-mapper-ref="contextMapper" role-prefix="ROLE_"
group-role-attribute="cn"/>
</security:authentication-manager>
<security:ldap-server id="ldapServer" url="ldap://localhost:10389/dc=oreilly,dc=com"
manager-dn="uid=admin,ou=system" manager-password="secret"/>
</beans>
注意我将两个管理器合二为一,其中包含两个身份验证提供程序。然后,我将<security:http />
元素合并为一个(因此不再需要将任何正则表达式或任何其他模式应用于它),现在有三个<security:intercept-url />
元素,两个来自第一个原始<security:http>
和第二个。