使用java完成ldap身份驗證

yf.z發表於2014-10-23

轉載自:http://www.cnblogs.com/lxlovezhd/archive/2013/05/29/3105350.html


一:LDAP

LDAP是Lightweight Directory Access Protocol的縮寫,即輕量級目錄訪問協議(這個主要是相對另一目錄訪問協議X.500而言的;LDAP略去了x.500中許多不太常用的功能,且以TCP/IP協議為基礎)。目錄服務和資料庫很類似,但又有著很大的不同之處。資料庫設計為方便讀寫,但目錄服務專門進行了讀優化的設計,因此不太適合於經常有寫操作的資料儲存。同時,LDAP只是一個協議,它沒有涉及到如何儲存這些資訊,因此還需要一個後端資料庫元件來實現。這些後端可以 是bdb(BerkeleyDB)、ldbm、shell和passwd等。

LDAP目錄以樹狀的層次結構來儲存資料(類同於DNS),最頂層即根部稱作“基準DN”,形如"dc=domain,dc=com"或者"o= domain.com",前一種方式更為靈活也是Windows AD中使用的方式。在根目錄的下面有很多的檔案和目錄,為了把這些大量的資料從邏輯上分開,LDAP像其它的目錄服務協議一樣使用OU (Organization Unit),可以用來表示公司內部機構,如部門等,也可以用來表示裝置、人員等。同時OU還可以有子OU,用來表示更為細緻的分類。

LDAP中每一條記錄都有一個唯一的區別於其它記錄的名字DN(Distinguished Name),其處在“葉子”位置的部分稱作RDN;如dn:cn=tom,ou=animals,dc=domain,dc=com中tom即為 RDN;RDN在一個OU中必須是唯一的。LDAP資料是“樹”狀的,這棵樹是可以無限延伸的.

LDAP 其實就是一個資料庫,但是跟我們平常的關聯式資料庫有所不同。關聯式資料庫是有一張一張的二維表格來存放資料的。ldap類似於dns系統,是樹狀的。用節點來存放資料。當然一個樹枝可以有n個節點,每個節點上存放的資料,都是以key => value的形式。就像dns系統。 .是根,下面是com,org,net,cn等等一些樹枝,這些樹枝下面還有abc.com, bcd.com等等樹枝。在每個樹枝下面都可以放節點,其實就是域名下面的主機:www,ftp,mail等等。所有的這些內容,組成了一個dns樹,在 ldap裡面叫資料庫。

儲存LDAP配置資訊及目錄內容的標準文字檔案格式是LDIF(LDAP Interchange Format),使用文字檔案來格式來儲存這些資訊是為了方便讀取和修改,這也是其它大多數服務配置檔案所採取的格式。LDIF檔案常用來向目錄匯入或更改記錄資訊,這些資訊需要按照LDAP中schema的格式進行組織,並會接受schema 的檢查,如果不符合其要求的格式將會出現報錯資訊。

在LDAP中目錄是按照樹型結構組織,目錄由條目(Entry)組成,條目相當於關聯式資料庫中表的記錄;條目是具有區別名DN(Distinguished Name)的屬性(Attribute)集合,DN相當於關聯式資料庫表中的關鍵字(Primary Key);屬性由型別(Type)和多個值(Values)組成,相當於關聯式資料庫中的域(Field)由域名和資料型別組成, 只是為了方便檢索的需要,LDAP中的Type可以有多個Value,而不是關聯式資料庫中為降低資料的冗餘性要求實現的各個域必須是不相關的。LDAP中條目的組織一般按照地理位置和組織關係進行組織,非常的直觀。LDAP把資料存放在檔案中,為提高效率可以使用基於索引的檔案資料庫,而不是關聯式資料庫。LDAP協議集還規定了DN的命名方法、存取控制方法、搜尋格式、複製方法、URL格式、開發介面等。LDAP對於這樣儲存這樣的資訊最為有用,也就是資料需要從不同的地點讀取,但是不需要經常更新。常見的屬性(Attribute)有:

二:在java中使用LDAP用於身份驗證

要想在一個應用程式進入之前使用LDAP進行身份驗證,在登入時後臺接收要登入的使用者名稱和密碼,首先新建用於驗證的類LDAPAuthentication

package com.hxkj.qrcode.action;
 
import java.util.Hashtable;
 
import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
 
public class LDAPAuthentication {
    private final String URL = "ldap://127.0.0.1:389/";
    private final String BASEDN = "ou=People,dc=example,dc=com";
    private final String FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";
    private LdapContext ctx = null;
    private final Control[] connCtls = null;
 
    private void LDAP_connect() {
        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, FACTORY);
        env.put(Context.PROVIDER_URL, URL + BASEDN);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
         
        String root = "cn=Directory Manager";// root
        env.put(Context.SECURITY_PRINCIPAL, root);
        env.put(Context.SECURITY_CREDENTIALS, "Admin123");
        // 此處若不指定使用者名稱和密碼,則自動轉換為匿名登入
        try {
            ctx = new InitialLdapContext(env, connCtls);
        } catch (javax.naming.AuthenticationException e) {
            System.out.println("驗證失敗:" + e.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    private String getUserDN(String uid) {
        String userDN = "";
        LDAP_connect();
        try {
            SearchControls constraints = new SearchControls();
            constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
            NamingEnumeration<SearchResult> en = ctx.search("", "uid=" + uid, constraints);
            if (en == null || !en.hasMoreElements()) {
                System.out.println("未找到該使用者");
            }
            // maybe more than one element
            while (en != null && en.hasMoreElements()) {
                Object obj = en.nextElement();
                if (obj instanceof SearchResult) {
                    SearchResult si = (SearchResult) obj;
                    userDN += si.getName();
                    userDN += "," + BASEDN;
                } else {
                    System.out.println(obj);
                }
            }
        } catch (Exception e) {
            System.out.println("查詢使用者時產生異常。");
            e.printStackTrace();
        }
 
        return userDN;
    }
 
    public boolean authenricate(String UID, String password) {
        boolean valide = false;
        String userDN = getUserDN(UID);
 
        try {
            ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userDN);
            ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
            ctx.reconnect(connCtls);
            System.out.println(userDN + " 驗證通過");
            valide = true;
        } catch (AuthenticationException e) {
            System.out.println(userDN + " 驗證失敗");
            System.out.println(e.toString());
            valide = false;
        } catch (NamingException e) {
            System.out.println(userDN + " 驗證失敗");
            valide = false;
        }
 
        return valide;
    }
}


相關文章