Spring security 是否可以使用Spring安全性(3.1.X)获取用户身份验证所针对的其他用户的LDAP信息?
我使用Spring安全性针对Active Directory服务器对用户进行身份验证。还将CustomUserContext注入LdapAuthenticationProviderbean,以提供对其他LDAP属性的访问。一切都很顺利。我可以从经过身份验证的用户那里获取我想要的任何东西 我遇到的问题是,我想从Active Directory服务器上检索一些属性,尤其是电子邮件地址,这些属性是登录用户以外的用户的属性。是否可以通过利用我已有的功能来实现这一点,或者我唯一的选择是使用完全独立的方法从不同的用户访问LDAP属性 [编辑] 配置如下 security-config.xmlSpring security 是否可以使用Spring安全性(3.1.X)获取用户身份验证所针对的其他用户的LDAP信息?,spring-security,ldap,Spring Security,Ldap,我使用Spring安全性针对Active Directory服务器对用户进行身份验证。还将CustomUserContext注入LdapAuthenticationProviderbean,以提供对其他LDAP属性的访问。一切都很顺利。我可以从经过身份验证的用户那里获取我想要的任何东西 我遇到的问题是,我想从Active Directory服务器上检索一些属性,尤其是电子邮件地址,这些属性是登录用户以外的用户的属性。是否可以通过利用我已有的功能来实现这一点,或者我唯一的选择是使用完全独立的方法从
<?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:sec="http://www.springframework.org/schema/security"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="contextSource" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="url" value="ldap://xxxx.xxxx.xxx:389" />
<property name="base" value="dc=corp,dc=global,dc=xxxxx,dc=com" />
<property name="userDn" value="CN=lna.authquery,OU=LDAPGroups,OU=NorthAmerica,DC=corp,DC=global,DC=xxxxx,DC=com" />
<property name="password" value="xxxxxxx" />
<property name="pooled" value="true" />
<!-- AD Specific Setting for avoiding the partial exception error -->
<property name="referral" value="follow" />
</bean>
<bean id="ldapAuthenticationProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider" >
<constructor-arg>
<bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="contextSource" />
<property name="userSearch">
<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value="" />
<constructor-arg index="1" value="(sAMAccountName={0})" />
<constructor-arg index="2" ref="contextSource" />
</bean>
</property>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="contextSource" />
<constructor-arg value="" />
<property name="groupSearchFilter" value="(member={0})" />
<property name="searchSubtree" value="true" />
<!-- Settings below convert the adds the prefix ROLE_ to roles returned from AD -->
</bean>
</constructor-arg>
<property name="userDetailsContextMapper">
<bean class="net.xxxx.xxxxx.utilities.CustomUserDetailsContextMapper" />
</property>
</bean>
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<constructor-arg>
<list>
<ref local="ldapAuthenticationProvider" />
</list>
</constructor-arg>
</bean>
<sec:http pattern="/css/**" security="none"/>
<sec:http pattern="/images/**" security="none"/>
<sec:http auto-config="true" authentication-manager-ref="authenticationManager" >
<sec:intercept-url pattern="/login.jsp*" requires-channel="https" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<sec:intercept-url pattern="/**" requires-channel="https" access="IS_AUTHENTICATED_FULLY"/>
<sec:form-login login-page='/login.jsp'
default-target-url="/home.html"
authentication-failure-url="/login.jsp" />
</sec:http>
CustomeUserDetails.java
package net.xxxx.xxxx.utilities;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
public class CustomUserDetails extends User {
private static final long serialVersionUID = 1416132138315457558L;
// extra instance variables
final String fullname;
final String email;
final String title;
public CustomUserDetails(String username, String password, boolean enabled, boolean accountNonExpired,
boolean credentialsNonExpired, boolean accountNonLocked,
Collection<? extends GrantedAuthority> authorities, String fullname,
String email, String title) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired,
accountNonLocked, authorities);
this.fullname = fullname;
this.email = email;
this.title = title;
}
public String getFullname() {
return this.fullname;
}
public String getEmail() {
return this.email;
}
public String getTitle() {
return this.title;
}
}
package net.xxxx.xxxx.utilities;
导入java.util.Collection;
导入org.springframework.security.core.GrantedAuthority;
导入org.springframework.security.core.userdetails.User;
公共类CustomUserDetails扩展了用户{
私有静态最终长serialVersionUID=1416132138315457558L;
//额外实例变量
最终字符串全名;
最终字符串电子邮件;
最后的字符串标题;
public CustomUserDetails(字符串用户名、字符串密码、启用布尔值、布尔值帐户非Expired、,
boolean CredentialsNoExpired,boolean accountNonLocked,
收藏我终于想出了如何做这件事。我回答这个问题是为了帮助其他需要做这件事的人。如果只有我一个人,我会感到惊讶
首先,我必须将我的security config.xml
文件移出WEB-INF结构,并将其放在spring资源目录下。我可以重用contextSource
bean。但是我不能重用CustomUserDetailsContextMapper.java
或CustomUserDetails.java
类,因为它们太复杂了特定于Spring安全性,而不仅仅是从未经身份验证的用户检索LDAP数据
最后,我为LDAP访问编写了一个单独的类,其中自动连接了公共contextSource
LdapDao.java
package net.xxxxx.xxx.dao;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import javax.naming.directory.Attributes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.stereotype.Component;
@Component
public class LdapDao {
LdapTemplate template;
@Autowired
public LdapDao(LdapContextSource contextSource) {
template = new LdapTemplate(contextSource);
}
@SuppressWarnings("unchecked")
public Map<String, String> getUserAttributes(String username) {
Map<String, String> results = new HashMap<String, String>();
String objectClass = "samAccountName=" + username;
LinkedList<Map<String, String>> list = (LinkedList<Map<String, String>>) template.search("", objectClass, new UserAttributesMapper());
if (!list.isEmpty()) {
// Should only return one item
results = list.get(0);
}
return results;
}
private class UserAttributesMapper implements AttributesMapper {
@Override
public Map<String, String> mapFromAttributes(Attributes attributes) throws javax.naming.NamingException {
Map<String, String> map = new HashMap<String, String>();
String fullname = (String) attributes.get("displayName").get();
String email = (String) attributes.get("mail").get();
String title = (String) attributes.get("title").get();
map.put("fullname", fullname);
map.put("email", email);
map.put("title", title);
return map;
}
}
}
package net.xxxxx.xxx.dao;
导入java.util.HashMap;
导入java.util.LinkedList;
导入java.util.Map;
导入javax.naming.directory.Attributes;
导入org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.ldap.core.AttributesMapper;
导入org.springframework.ldap.core.LdapTemplate;
导入org.springframework.ldap.core.support.LdapContextSource;
导入org.springframework.stereotype.Component;
@组成部分
公共类LdapDao{
LdapTemplate;
@自动连线
公共LdapDao(LdapContextSource contextSource){
模板=新的LdapTemplate(contextSource);
}
@抑制警告(“未选中”)
公共映射getUserAttributes(字符串用户名){
映射结果=新的HashMap();
String objectClass=“samAccountName=”+用户名;
LinkedList=(LinkedList)template.search(“”,objectClass,new UserAttributesMapper());
如果(!list.isEmpty()){
//应该只返回一个项目
结果=list.get(0);
}
返回结果;
}
私有类UserAttributesMapper实现AttributesMapper{
@凌驾
公共映射mapFromAttributes(Attributes Attributes)抛出javax.naming.NamingException{
Map Map=newhashmap();
String fullname=(String)attributes.get(“displayName”).get();
String email=(String)attributes.get(“邮件”).get();
String title=(String)attributes.get(“title”).get();
map.put(“全名”,全名);
map.put(“email”,email);
地图放置(“标题”,标题);
返回图;
}
}
}
@Bill你所做的很好,尽管实际上有一个更简单的方法。不要求助于LdapTemplate
,只需使用你已经注册了defaultldapauthoritiespoolator
和filterbasedapusersearch
的bean。这样你可以得到同样的UserDetails
对象当局是否已为您的net.xxxx.xxxxx.utilities.CustomUserDetailsContextMapper
填充并重用您的现有代码
以下是您需要做的:
将需要作为命名bean注入的been分离出来,并为属性和构造函数arg使用ref
属性(defaultldaputhoritiespoolator
,filterbasedapusersearch
,net.xxxx.xxxxx.utilities.CustomUserDetailsContextMapper
)
在LdapDao
中,将引用注入到:
filterbasedapusersearch
-userSearch
defaultldaAuthoritiesPopulator
-authPop
net.xxxx.xxxxx.utilities.CustomUserDetailsContextMapper
-userMapper
将以下方法添加到LdapDao
:
public UserDetails getUserDetails(最终字符串用户名){
试一试{
DirContextOperations ctx=userSearch.searchForUser(用户名);
返回userMapper.mapUserFromContext(ctx,用户名,
authPop.getGrantedAuthories(ctx,用户名));
}捕获(UsernameNotFoundException-ex){
返回null;
}
}
现在您只需调用getUser即可
package net.xxxxx.xxx.dao;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import javax.naming.directory.Attributes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.stereotype.Component;
@Component
public class LdapDao {
LdapTemplate template;
@Autowired
public LdapDao(LdapContextSource contextSource) {
template = new LdapTemplate(contextSource);
}
@SuppressWarnings("unchecked")
public Map<String, String> getUserAttributes(String username) {
Map<String, String> results = new HashMap<String, String>();
String objectClass = "samAccountName=" + username;
LinkedList<Map<String, String>> list = (LinkedList<Map<String, String>>) template.search("", objectClass, new UserAttributesMapper());
if (!list.isEmpty()) {
// Should only return one item
results = list.get(0);
}
return results;
}
private class UserAttributesMapper implements AttributesMapper {
@Override
public Map<String, String> mapFromAttributes(Attributes attributes) throws javax.naming.NamingException {
Map<String, String> map = new HashMap<String, String>();
String fullname = (String) attributes.get("displayName").get();
String email = (String) attributes.get("mail").get();
String title = (String) attributes.get("title").get();
map.put("fullname", fullname);
map.put("email", email);
map.put("title", title);
return map;
}
}
}