具有Active Directory和数据库角色的Spring安全性
我正在尝试将Spring安全性与Active Directory用户名和密码一起使用。此外,我还有一个数据库角色表,它与包含Active Directory用户名的用户表有关系(用户表与Active Directory没有任何关系,它是完全独立的,我只是将用户名放在该表中,以便将其与角色匹配) 我遵循这个例子 问题是我看不到CustomUserDetailsService类的loadUserByUsername方法中使用密码的位置具有Active Directory和数据库角色的Spring安全性,spring,spring-security,active-directory,Spring,Spring Security,Active Directory,我正在尝试将Spring安全性与Active Directory用户名和密码一起使用。此外,我还有一个数据库角色表,它与包含Active Directory用户名的用户表有关系(用户表与Active Directory没有任何关系,它是完全独立的,我只是将用户名放在该表中,以便将其与角色匹配) 我遵循这个例子 问题是我看不到CustomUserDetailsService类的loadUserByUsername方法中使用密码的位置 public UserDetails loadUserByUs
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
org.krams.domain.User domainUser = userRepository.findByUsername(username);
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
return new User(
domainUser.getUsername(),
domainUser.getPassword().toLowerCase(),
enabled,
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
getAuthorities(domainUser.getRole().getRole()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
据我所知,这一行根据数据库userRepository.findByUsername(username)验证用户名代码>
但是我如何在那里使用lpad验证呢?我可以在这里使用类似身份验证实现的东西吗
更新:
我正在尝试让它与CustomUserDetailsContextMapper一起工作
XML
<authentication-manager >
<authentication-provider ref="ldapActiveDirectoryAuthProvider" />
</authentication-manager>
<beans:bean id="ldapActiveDirectoryAuthProvider"
class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<beans:constructor-arg value="domain" />
<beans:constructor-arg value="ldap://NAME/"/>
<beans:property name="userDetailsContextMapper" ref="tdrUserDetailsContextMapper"/>
<beans:property name="useAuthenticationRequestCredentials" value="true"/>
</beans:bean>
<beans:bean id="tdrUserDetailsContextMapper" class="com.test8.security8.service.CustomUserDetailsContextMapper"/>
自定义类
public class CustomUserDetailsContextMapper implements UserDetailsContextMapper, Serializable{
private static final long serialVersionUID = 3962976258168853984L;
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authority) {
String role="admin";
System.out.println("TEST");
if(username.equals("usuario"))role="admin";
else role="user";
List authList = getAuthorities(role);
return new User(username, "", true, true, true, true, authList);
}
private List getAuthorities(String role) {
List authList = new ArrayList();
authList.add(new SimpleGrantedAuthority("ROLE_USER"));
//you can also add different roles here
//for example, the user is also an admin of the site, then you can add ROLE_ADMIN
//so that he can view pages that are ROLE_ADMIN specific
if (role != null && role.trim().length() > 0) {
if (role.equals("admin")) {
authList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
}
return authList;
}
@Override
public void mapUserToContext(UserDetails arg0, DirContextAdapter arg1) {
// TODO Auto-generated method stub
}
}
公共类CustomUserDetailsContextMapper实现UserDetailsContextMapper,可序列化{
私有静态最终长serialVersionUID=396297625816853984L;
@凌驾
公共UserDetails mapUserFromContext(DirContextOperations ctx、字符串用户名、集合我最终使用了M.Deinum建议的UserDetailsContextMapper。我还创建了customs SpringSecurityLdapTemplate和ActiveDirectoryLdapAuthenticationProvider
在自定义ActiveDirectoryLdapAuthenticationProvider中,我更改了以下方法:
private LdapContext bindAsUser(String username, String password) {
// TODO. add DNS lookup based on domain
final String bindUrl = url;
Hashtable<String,String> env = new Hashtable<String,String>();
env.put(Context.SECURITY_AUTHENTICATION, "simple");
String bindPrincipal = createBindPrincipal(username);
env.put(Context.SECURITY_PRINCIPAL, bindPrincipal);
env.put(Context.PROVIDER_URL, bindUrl);
env.put(Context.SECURITY_CREDENTIALS, password);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.REFERRAL, "follow");
try {
return new InitialLdapContext(env, null);
} catch (NamingException e) {
if ((e instanceof AuthenticationException) || (e instanceof OperationNotSupportedException)) {
handleBindException(bindPrincipal, e);
throw badCredentials();
} else {
throw LdapUtils.convertLdapException(e);
}
}
}
private LdapContext bindauser(字符串用户名、字符串密码){
//TODO.添加基于域的DNS查找
最后一个字符串bindUrl=url;
Hashtable env=新的Hashtable();
环境put(Context.SECURITY_认证,“simple”);
字符串bindPrincipal=createBindPrincipal(用户名);
环境保护(Context.SECURITY_PRINCIPAL,bindPrincipal);
env.put(Context.PROVIDER\uURL,bindUrl);
环境放置(Context.SECURITY\u凭证、密码);
put(Context.INITIAL\u Context\u工厂,“com.sun.jndi.ldap.LdapCtxFactory”);
环境投入(Context.reference,“follow”);
试一试{
返回新的InitialLdapContext(env,null);
}捕获(NamingE例外){
if((e instanceof AuthenticationException)| |(e instanceof operation notsupportedexception)){
车把异常(bindPrincipal,e);
抛出错误凭据();
}否则{
抛出LdapUtils.convertLdapException(e);
}
}
}
这句话对我来说很重要:env.put(Context.reference,“follow”);
在SpringSecurityLdapTemplate自定义类中
public static DirContextOperations searchForSingleEntryInternal(DirContext ctx, SearchControls searchControls,
String base, String filter, Object[] params) throws NamingException {
final DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
final DistinguishedName searchBaseDn = new DistinguishedName(base);
final NamingEnumeration<SearchResult> resultsEnum = ctx.search(searchBaseDn, filter, params, buildControls(searchControls));
filter, searchControls);
if (logger.isDebugEnabled()) {
logger.debug("Searching for entry under DN '" + ctxBaseDn
+ "', base = '" + searchBaseDn + "', filter = '" + filter + "'");
}
Set<DirContextOperations> results = new HashSet<DirContextOperations>();
try {
while (resultsEnum.hasMore()) {
SearchResult searchResult = resultsEnum.next();
DirContextAdapter dca = new DirContextAdapter();
//dca=(DirContextAdapter) searchResult.getObject();
Assert.notNull(dca, "No object returned by search, DirContext is not correctly configured");
if (logger.isDebugEnabled()) {
logger.debug("Found DN: " + dca.getDn());
}
results.add(dca);
}
} catch (PartialResultException e) {
LdapUtils.closeEnumeration(resultsEnum);
logger.info("Ignoring PartialResultException");
}
if (results.size() == 0) {
throw new IncorrectResultSizeDataAccessException(1, 0);
}
if (results.size() > 1) {
throw new IncorrectResultSizeDataAccessException(1, results.size());
}
return results.iterator().next();
}
public static DirContextOperations searchForSingleEntryInternal(DirContext ctx、SearchControls、SearchControls、,
字符串基、字符串筛选器、对象[]参数)引发NamingException{
final differentiedname ctxBaseDn=新的differentiedname(ctx.getNameInNamespace());
最终区分名称searchBaseDn=新的区分名称(基本);
最终NamingEnumeration resultsEnum=ctx.search(searchBaseDn、过滤器、参数、构建控件(searchControls));
过滤、搜索和控制);
if(logger.isDebugEnabled()){
logger.debug(“搜索DN下的条目””+ctxBaseDn
+“,base='”+searchBaseDn+”,filter='“+filter+””;
}
Set results=new HashSet();
试一试{
while(resultnum.hasMore()){
SearchResult SearchResult=resultsum.next();
DirContextAdapter dca=新的DirContextAdapter();
//dca=(DirContextAdapter)searchResult.getObject();
notNull(dca,“搜索未返回任何对象,DirContext未正确配置”);
if(logger.isDebugEnabled()){
debug(“找到DN:+dca.getDn());
}
结果:添加(dca);
}
}捕获(PartialResultException e){
LdapUtils.closeEnumeration(resultsum);
info(“忽略PartialResultException”);
}
如果(results.size()==0){
抛出新的IncorrectResultSizeDataAccessException(1,0);
}
如果(results.size()>1){
抛出新的IncorrectResultSizeDataAccessException(1,results.size());
}
返回results.iterator().next();
}
这对我来说很有效,但这是一个非常特殊的场景。多亏M.Deinum为我指明了正确的方向。正如该方法所建议的,你不会看不到任何东西,这只是用于加载用户名。密码检查在其他地方处理。在本例中,在这一行中获得了一个用户对象:domainUser=userRepository.findByUsername(用户名)。我想这样做,但是对于Active Directory用户,您是否花时间阅读了说明如何使用Active Directory的?实现自定义UserDetailsContextMapper
以访问用户名并从数据库检索角色,其余信息可以来自LDAP身份验证。我不知道hink我明白,:(.我试图围绕我指出的示例构建一个解决方案。但使用UserDetailsContextMapper似乎是另一种方法。我是否应该实现UserDetailsContextMapper而不是UserDetailsService并以相同的方式使用它?该示例适用于JPA而不是Active Directory。