公司里有好几个工作用的平台,其中之一是个网盘,选型使用了 Kiftd。这个系统是个个人开发者开发的,因为现在公司内部使用的量不大,所以在核心功能上还没有感觉到问题,一个比较不爽的地方在于它不支持 LDAP 认证登录,这在用户管理上就带来了额外的工作。一年过去了,作者还没有把这个功能加上,在它的项目 issue 里可以看到其他用户也有类似的需求,所以就琢磨着要不要自己把这个功能补上。
困难当然是有的,第一,俺不是个 Java 程序员,第二 OpenLDAP 也不熟,二十年前倒是接触过,基本忘光了。首先按照网络上的教程,把 Visual Studio Code 里的 Java 开发环境搭建好了。将以下代码存为 LdapService.java,然后运行 main 函数即可。此代码也来源于网上,由于原来的版本依赖有其他的东西(主要是个 Logger),我做了精简,输出就粗暴地使用 System.out 了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
import java.util.Hashtable; import javax.naming.Context; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; public class LdapService { // LDAP 服务器的 URL 地址,TODO: 换为你的真实服务器地址 private final String LDAP_URL = "ldap://www.xxx.yyy.zzz:389"; /** * LDAP 验证用户登录 */ public boolean authenticate(final String userName, final String password) { // env 中的 key 都是固定值,在 javax.naming.Context 类中 final Hashtable<String, String> env = new Hashtable<String, String>(4); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, LDAP_URL); // ldapURL env.put(Context.SECURITY_AUTHENTICATION, "simple"); // ldapAuthMode // 连接的主要凭证就是此处的 dn,这个东东非常坑,大部分人都在这儿会栽进去。 // 要点在于,dn 要完整!然鹅,大部分程序员不知道什么样才是一个完整的 dn, // 我的经验是,打开 LDAP Account Manager,使用“树状结构”展示,选中任一 // 用户均会显示出其完整的 dn。 String dn = "cn=" + userName + ",ou=People,dc=chainsguard,dc=com"; env.put(Context.SECURITY_PRINCIPAL, dn); env.put(Context.SECURITY_CREDENTIALS, password); boolean ret = false; DirContext ctx = null; try { // 这条代码执行成功就是验证通过 ctx = new InitialDirContext(env); ret = true; } catch (final Exception e) { System.out.println(e.getMessage()); } finally { try { if (ctx != null) { ctx.close(); ctx = null; } env.clear(); } catch (final Exception e) { } } return ret; } public static void main(String args[]) { final LdapService ldap = new LdapService(); final Boolean succeeded = ldap.authenticate( "renwoxing", "12345654321" // TODO: 换用你的用户凭证 ); System.out.println(succeeded ? "That's OK!" : "That's NOT OK!"); } } |
遗留问题:LDAP 有个叫 RDN 的东东,决定了用户的 DN 组成形式。目前在我的系统中,界面手动操作添加的用户,其 RDN 是 uid,而另一个同事用程序把之前其他地方的用户导入进去,其 RDN 是 cn,这个会干扰上面的 dn 拼接部分的代码,正在试图搞清楚如何处理是最优方案,也许需要用搜索来认证。