我在Spring MVC项目中使用经过LDAP身份验证的Spring Security 3。 它工作正常,直到我需要将我的项目部署到其他环境并将JDK的版本从1.6更改为1.7。
下面是我的spring安全配置文件和示例代码:
1)security-application-Context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:s="http://www.springframework.org/schema/security"
xmlns="http://www.springframework.org/schema/beans"
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-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<s:http use-expressions="true">
<s:intercept-url pattern="/auth/**" access="permitAll" />
<s:intercept-url pattern="/css/**" access="permitAll" />
<s:intercept-url pattern="/image/**" access="permitAll" />
<s:intercept-url pattern="/scripts/**" access="permitAll" />
<s:intercept-url pattern="/**" access="hasRole('GENERAL_USER')" />
<s:form-login login-page="/auth/login.html"
default-target-url="/welcome.html"
authentication-failure-url="/auth/login.html?error=1" />
<s:access-denied-handler error-page="/auth/denied.html"/>
<s:logout invalidate-session="true" logout-success-url="/auth/logoutSuccess.html"/>
</s:http>
<s:authentication-manager>
<s:authentication-provider ref="ldapAuthProvider" />
</s:authentication-manager>
<bean
id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource"
scope="singleton">
<constructor-arg
value="ldap://ldapurl:389/dc=o,dc=a" />
<property name="userDn" value="cn=xxx,cn=users,dc=o,dc=a" />
<property name="password" value="password" />
<property name="baseEnvironmentProperties">
<map>
<entry key="java.naming.referral">
<value>follow</value>
</entry>
</map>
</property>
</bean>
<bean id="userSearch"
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<!-- searchBase, searchFilter, contextSource -->
<constructor-arg index="0" value="" />
<constructor-arg index="1" value="(sAMAccountName={0})" />
<constructor-arg index="2" ref="contextSource" />
</bean>
<bean id="ldapAuthProvider"
class="com.foo.auth.MyLdapAuthenticationProvider">
<constructor-arg>
<bean
class="com.foo.auth.MyLdapAuthenticator">
<constructor-arg ref="contextSource" />
<property name="userSearch">
<ref bean="userSearch" />
</property>
</bean>
</constructor-arg>
<property name="authoritiesPopulator" ref="authoritiesPopulator" />
<property name="userDetailsContextMapper" ref="userDetailsMapper" />
</bean>
<bean id="authoritiesPopulator" class="com.foo.auth.MyLdapAuthoritiesPopulator">
<constructor-arg ref="userService" />
</bean>
<bean id="userService" class="com.foo.auth.MyLdapUserDetailsService">
<constructor-arg ref="userSearch" />
<property name="userDetailsMapper" ref="userDetailsMapper" />
</bean>
<bean id="userDetailsMapper" class="com.foo.auth.MyUserDetailsContextMapper">
</bean>
</beans>
2)成功登录后会将url重定向到welcome.jsp,在welcome.jsp中,我使用spring security taglib来获取登录用户的全名。 (对于测试,我使用principal来显示整个上下文信息):
<security:authentication property="principal"></security:authentication>
当使用JDK 1.6时,校长显示:
com.foo.auth.MyUserDetails@3e2d20ec:.........
我可以使用我的自定义UserDetail属性,例如principal.fullName。 当使用JDK 1.7时,校长显示:
org.springframework.security.ldap.userdetails.LdapUserDetailsImpl@86dae957:...
它没有获取我的自定义UserDetail对象。所以如果我使用JDKk1.7,我就无法正确获取Spring上下文。
这个问题花了我差不多1周的时间才发现根本原因是JDK版本的问题; - (
有谁知道为什么使用LDAP的Spring安全性在JDK1.7中不起作用?或者我想念配置的东西?
提前谢谢你!
答案 0 :(得分:1)
问题已解决。 这是因为我的MyLdapAuthenticationProvider扩展了错误的提供者。 我将MyLdapAuthenticationProvider扩展类更改为LdapAuthenticationProvider, 现在JDK 1.6和1.7中的弹簧安全性都很好。
这是我的自定义LdapAuthenticationProvider:
public class MyLdapAuthenticationProvider extends LdapAuthenticationProvider {
private static Logger logger = Logger.getLogger(MyLdapAuthenticationProvider.class);
private MyLdapAuthenticator authenticator;
@Autowired
private MyLdapAuthoritiesPopulator authoritiesPopulator;
@Autowired
private MyUserDetailsContextMapper userDetailsContextMapper;
public MyLdapAuthenticationProvider(LdapAuthenticator authenticator) {
super(authenticator);
this.authenticator = (MyLdapAuthenticator) authenticator;
}
@Override
protected DirContextOperations doAuthentication(UsernamePasswordAuthenticationToken userToken) {
try {
DirContextOperations dirCtx = getAuthenticator().authenticate(userToken);
return dirCtx;
} catch (PasswordPolicyException ppe) {
throw new LockedException(this.messages.getMessage(ppe.getStatus().getErrorCode(), ppe.getStatus()
.getDefaultMessage()));
} catch (UsernameNotFoundException notFound) {
throw new BadCredentialsException("User Name Error!");
} catch (NamingException ldapAccessFailure) {
throw new AuthenticationServiceException(ldapAccessFailure.getMessage(), ldapAccessFailure);
}
}
private void setAuthenticator(MyLdapAuthenticator authenticator) {
Assert.notNull(authenticator, "An LdapAuthenticator must be supplied");
this.authenticator = authenticator;
}
private MyLdapAuthenticator getAuthenticator() {
return authenticator;
}
public MyUserDetailsContextMapper getUserDetailsContextMapper() {
return userDetailsContextMapper;
}
public void setUserDetailsContextMapper(MyUserDetailsContextMapper userDetailsContextMapper) {
this.userDetailsContextMapper = userDetailsContextMapper;
}
public void setAuthoritiesPopulator(MyLdapAuthoritiesPopulator authoritiesPopulator) {
this.authoritiesPopulator = authoritiesPopulator;
}
public MyLdapAuthoritiesPopulator getAuthoritiesPopulator() {
return authoritiesPopulator;
}
}