簡述
前陣子因爲項目需要用到 LDAP ,發現從百度搜到的結果很少專一針對認證LDAP密碼認證代碼例子,廢了很多功夫,很多的例子都是隻是單單連接LDAP服務器(ctx = new InitialDirContext(env);)就完事了。所以特意奉上一段代碼,對密碼認證的。當然主要是對 獲取某個DN下面的屬性值進行對比 這樣的一個操作。理論的話就不多說了,如果想了解 LDAP 以及想去了解調用LDAP接口的可以移步到我上一條轉載的博客 【Java LDAP操作】http://blog.csdn.net/charlven/article/details/78032221 。
實現方式:
方式一:最簡單的賬號密碼認證方式
直接拿到用戶的賬號密碼即可認證,沒什麼可描述的,直接上代碼!
代碼示例
try {
String username=email.split("@")[0]; //uid
String bindUserDN = "uid="+username+",ou=people,dc=department"; //用戶 DN
String bindPassword = "*****"; //用戶密碼
String url = "ldap://127.0.0.1:389/"; //ldap服務器IP
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(javax.naming.Context.PROVIDER_URL, url);
env.put(javax.naming.Context.SECURITY_AUTHENTICATION, "simple");
env.put(javax.naming.Context.SECURITY_PRINCIPAL, bindUserDN);
env.put(javax.naming.Context.SECURITY_CREDENTIALS, bindPassword);
javax.naming.directory.DirContext ctx = new javax.naming.directory.InitialDirContext(env);
return "OK";
} catch (Exception e) {
// todo log
return "FAILED";
}
方式二:手動獲取節點下的屬性值進行校驗
這種方式有點複雜,首先我們來整理一下獲取LDAP密碼認證的整體邏輯思路:
-
收集LDAP服務器信息 : 連接LDAP服務器賬號和密碼(連接每一個服務器都是需要賬號密碼的,就想連接MySql也需要密碼),LDAP服務器 IP 地址 , 端口(Port) ,密碼存在於 LDAP 服務器中的DN 、以及密碼在該 DN 下的屬性名 Attr 。
String bindLdapUser; String bindLdapPassword; String baseDN; String ldapIp; String port; String mapAttr;
-
收集了以上信息之後開始對進行編碼連接 LDAP 進行驗證了。
(1) 建立連接 ctx = new InitialDirContext(env);
(2) 定義 SearchControls();調用 DirContext.search 方法。
(3) 對search出來的結果NamingEnumeration進行遍歷,因爲search是獲取當前節點下的所有支節點,不單單只是獲取一個對象,如果想獲取一個對象,可以調用lookup()方法。當然如果search()方法中依靠filter可以定位到一個對象節點,效果和lookup也是一樣的。
(4) 遍歷過程中獲取相應的Attributes。這個Attributes就是當前節點的所有屬性,比如說當前節點是DN : sid=admin,ou=People,o=test ,那麼獲取出來的Attributes裏面的屬性將會是在此DN下你增加的所有屬性比如(username=admin,password=123456,partment=xx,age=16…)。這裏我們獲取其中的密碼所以是Attribute attr = attrs.get("password"); String ldapPassword = (String)attr.get(); //獲取出來的 ldapPassword 就是123456
(5) 獲取出來之後再對你傳入的 requestPwd 和 ldap 獲取出來的 ldapPassword 進行對比
requestPwd.equals(ldapPassword);
代碼示例
接下來直接貼上詳細的代碼,因爲當時做的是認證,所以直接寫成一個認證方法:
private Map<String, Object> auth(String password, String userName) throws NamingException { String bindLdapUser = "root"; // 連接LDAP服務器的管理員賬號密碼 String bindLdapPwd = "123456"; String ldapBaseDN = "ou=People,o=test"; // 這個根據自己需要更改 String attrName = "password"; // 獲取DN下面的屬性名 String port = "389"; // ldap 服務器佔用的端口號 String ldapIp = "192.168.120.222"; // ldap 服務器的IP地址 String url = "ldap://" + ldapIp + ":" + port + '/' + ldapBaseDN; System.console().printf("[auth ldap] ldap url : " + url); Hashtable<String, Object> env = new Hashtable<String, Object>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_CREDENTIALS, bindLdapPwd); env.put(Context.SECURITY_PRINCIPAL, bindLdapUser); env.put(Context.PROVIDER_URL, url); DirContext ctx = null; try { // Ldap link ctx = new InitialDirContext(env); System.console().printf("[auth ldap linked] InitialDirContext success"); // Ldap search SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); String filter = "sid" + userName;// 加上filter之後DN就變成sid={userName},ou=People,o=test NamingEnumeration<?> nameEnu = ctx.search("", filter, searchControls); System.console().printf("[step1 ladp linked] begin to search, filter :" + filter); if (nameEnu == null) { // User Not Found System.console().printf("[step error] DirContext.search() return null. filter : " + filter); return createResult(104, 2001, "User Not Found"); } else { System.console().printf("[step2 ldap] Begin to print elements"); String ldapUserPwd = null; while (nameEnu.hasMore()) { System.console().printf("[step3 ldap] nameEnu element is not null"); Object obj = nameEnu.nextElement(); System.console().printf(obj.toString()); if (obj instanceof SearchResult) { System.console().printf("[step4 ldap] obj instanceof SearchResult"); SearchResult result = (SearchResult) obj; Attributes attrs = result.getAttributes(); if (attrs == null) { // Password Error System.console().printf("[step error] SearchResult.getAttrbutes() is null. "); return createResult(102, 4003, "Password Error"); } else { System.console().printf("[step5 ldap] begin to get attribute : " + attrName); // attrName就是屬性名 Attribute attr = attrs.get(attrName); if (attr != null) { System.console().printf("[step6 ldap] attribute is not null."); ldapUserPwd = (String) attr.get(); System.console().printf("[step7 print ldapPwd] the ldap password is : *********"); System.console().printf("[step7 print ldapPwd] the request password is : *********"); if (password.equalsIgnoreCase(ldapUserPwd)) { // OK System.console().printf("[step8 ldap] equals password , success ."); return createResult(0, 0, "OK"); } else { // Password Error System.console().printf("[step9 ldap] equals password , failure . password is not same ."); return createResult(102, 4003, "Password Error"); } } } } } System.console().printf("[step error] while end . ldapUserPwd is null , can't find password from ldap ."); return createResult(102, 4003, "Password Error"); } } catch (NamingException e) { e.printStackTrace(); System.console().printf("[ldap link failed] message :" + e.getMessage()); throw e; } finally { if (ctx != null) { ctx.close(); } } } private Map<String, Object> createResult(int ret, int code, String msg) { Map<String, Object> result = WmsvrFactory.createParamsObj(); result.put("ret", ret); result.put("code", code); result.put("msg", msg); return result; }