LDAP密碼認證(驗證)講解與實踐

簡述

  前陣子因爲項目需要用到 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密碼認證的整體邏輯思路:

  1. 收集LDAP服務器信息 : 連接LDAP服務器賬號和密碼(連接每一個服務器都是需要賬號密碼的,就想連接MySql也需要密碼),LDAP服務器 IP 地址 , 端口(Port) ,密碼存在於 LDAP 服務器中的DN 、以及密碼在該 DN 下的屬性名 Attr

    String bindLdapUser;
    String bindLdapPassword;
    String baseDN;
    String ldapIp;
    String port;
    String mapAttr;
    
  2. 收集了以上信息之後開始對進行編碼連接 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;
    }
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章