更新at 20200828:
重要!!!
其实不需要ldaptemplate
java已经集成了ldap,直接调用就行了
但是,一点需要注意。关于cn&ou
cn&ou反正就是组织结构吧
ad服务器自带的目录需要用cn访问
但是自建的目录需要用ou
如:ou=myorg,dc=domain,dc=com
网上的资料只是大致解释了下CN&OU
OU--组织单元,CN--用户名或者服务器名
但是微软ad服务器自带的Users目录却是需要CN访问的
总之这两者的概念及其不好理解
总之,自建的组织单元用OU,自带的用CN
重要:不像那些网上能随便查到的连篇赘述,本文是对要点和天坑做一个总结。
**
本文主旨–标题上都有了
要点:
1,springboot集成ldapTemplate;
2,搭建windows server的ad域控服务器;
3,两者对接实现身份验证;
前提
1,你先得明白什么是域控,ad和ldap是什么东西。
个人理解–域控就是管控局域网内设备安全问题的一种手段。完成验证后设备间才能互相访问之类的。这样的表述多半是不严谨的,但我本就不需要也不想关心这部分内容。域控对我来说,就是一个统一帐号管理平台。甲方的需求是–不需要在我们系统中另建帐号,能直接使用域控帐号,就是帐号一卡通嘛。
2,基础概念
域控是基于一个域名的。
dc,uid等一些概念必须要了解。
dc相当于域名吧,ou,cn等都是层级组织,文件夹和文件的关系。uid是用户唯一标识。
window的ad域控涉及另外两个概念userprincipalname和sAMAccountName,反正就是用来标识用户名的,自行百度即可。
所有这些术语,只需要围绕两点去理解–账户和密码,其余的照网上那些例程的样子去填就行了。
要点详述
要点1,2网上有很多教程。尤其要点2实在没啥可讲的,搭建好后创建一个测试帐号就行了。
我先前使用过openldap来测试,我劝你直接放弃,直接怼windows server吧。因为,标准ldap在账户这一概念上就和windows存在区别。另外,最重要的是openldap处理身份验证时,有不明原因造成的天量延迟。经过我跟源码+查看运行情况,基本确定了是openldap自己的锅,或者是我访问姿势不对。因为,每次验证都会造成openldap所在进程狂飙cpu占比。网上查了n多资料都没有提及的。考虑到openldap本就是拿来临时测试的,就果断放弃,立马整了台云服务器自建一套windows ad域控。
要点3
下文上半段是配置,下半段是controller中如何去验证人员身份。
你看根本不需要关心什么cn不cn,拿到管理员帐号和密码,创建LdapTemplate。再凭人员帐号和密码去访问就完事了。
@Bean
public LdapContextSource contextSource() {
LdapContextSource contextSource = new LdapContextSource();
Map<String, Object> config = new HashMap();
contextSource.setUrl("ldap://localhost:389");
// contextSource.setBase("dc=maxcrc,dc=com");
// contextSource.setUserDn("cn=Manager,dc=maxcrc,dc=com");
// contextSource.setPassword("secret");
contextSource.setBase("dc=catectest,dc=com");
contextSource.setUserDn("Administrator@catectest.com");
contextSource.setPassword("******");
// 解决 乱码 的关键一句
config.put("java.naming.ldap.attributes.binary", "objectGUID");
// config.put("com.sun.jndi.ldap.read.timeout","3000");
contextSource.setPooled(false);
contextSource.setBaseEnvironmentProperties(config);
return contextSource;
}
@Bean
public LdapTemplate ldapTemplate() {
if (null == ldapTemplate)
ldapTemplate = new LdapTemplate(contextSource());
ldapTemplate.setIgnorePartialResultException(true);
return ldapTemplate;
}
@RequestMapping(value = "/testLdap3", method = RequestMethod.GET)
public ComAckDto<Boolean> testLdap3(@RequestParam String username, @RequestParam String passWord) {
EqualsFilter filter = new EqualsFilter("userPrincipalName",username);
boolean res = ldapTemplate.authenticate("",filter.toString(), passWord);
return new ComAckDto<>(0, 0, res);
}
@RequestMapping(value = "/testLdap4", method = RequestMethod.GET)
public ComAckDto<Boolean> testLdap4(@RequestParam String username, @RequestParam String passWord) {
EqualsFilter filter = new EqualsFilter("sAMAccountName", username);
boolean res = ldapTemplate.authenticate("",filter.toString(), passWord);
return new ComAckDto<>(0, 0, res);
}
总结(很重要)
此处是小结+列举下天坑们
一,关于openldap
1,不要用openldap去测试,它在验证身份时有不明卡顿和cpu占用异常;
2,openldap会让你去涉及什么cn,dn,ou这些本来你不需要关心的东西。各种参数填写能把你脑袋搅拌成浆糊。
让你迷失在谜一样的接口中。并且让你和windows的参数定义混淆。你会发现ldap的objectclass、cn,dn,ou、uip,
完全和windows的userprincipalname和sAMAccountName对不上,一看就不是一个娘生的。
二,关于windows的ad域控
1,围绕帐号+密码。帐号就分两种userprincipalname和sAMAccountName。
userprincipalname的风格是这样的---name@area.com(上文testLdap3中的username)
sAMAccountName的风格--name,不要被windows上那个显示“area\name”蛊惑,你验证的时候就填写name就行了。
(上文testLdap4中的username为name)
至于base就是--dc=area,dc=com
三,额外
1,ldapTemplate.setIgnorePartialResultException(true);这就配置千万别忘了,不然验证时报异常的。
在stackoverflow上找的解决办法,原理懒得去深究了。
四,遗留
openldap上获取账户信息时倒是顺畅的。windows上获取账户信息因为用不到且试了几下不行,就不去深究了。
再总结
一句话–搭建好windows server的域控服务后,springboot集成ldapTemplate,然后用userprincipalname或sAMAccountName属性去做身份验证就行了。
userprincipalname=name@area.com
sAMAccountName=name
一定要懂得抽丝剥茧,往往一篇文章就像一堆稻草,对你有用的就只有那一根。