首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

封裝 JNDI 操作 LDAP 服務的工具類(四之二):進階搜尋、群組維護與認證整合

     編輯:Java 相關知識

進階搜尋功能:三大模式全覆蓋

1. 子樹搜尋(回傳所有屬性)

public static List> searchContextSub(DirContext context, String cn, String filter)
        throws NamingException {
    List> resultList = new ArrayList<>();
    SearchControls ctls = new SearchControls();
    ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);

    NamingEnumeration results = context.search(cn, filter, ctls);
    while (results != null && results.hasMore()) {
        SearchResult sr = (SearchResult) results.next();
        Attributes attrs = sr.getAttributes();
        if (attrs == null) continue;

        Map row = new HashMap<>();
        for (NamingEnumeration ae = attrs.getAll(); ae.hasMoreElements(); ) {
            Attribute attr = (Attribute) ae.next();
            String attrId = attr.getID();
            NamingEnumeration vals = attr.getAll();
            if (vals == null) continue;

            List valList = new ArrayList<>();
            while (vals.hasMoreElements()) {
                Object v = vals.nextElement();
                if (v != null) valList.add(v);
            }
            row.put(attrId, valList.size() == 1 ? valList.get(0) : valList);
        }
        resultList.add(row);
    }
    return resultList;
}

2. 子樹搜尋(指定回傳屬性,效能最佳)

public static List> searchContextSub(DirContext context, String cn,
        String filter, String[] returnedAtts) throws NamingException {
    List> resultList = new ArrayList<>();
    SearchControls ctls = new SearchControls();
    ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    ctls.setReturningAttributes(returnedAtts); // 關鍵:只傳輸需要屬性

    NamingEnumeration results = context.search(cn, filter, ctls);
    // 迭代邏輯同上,略...
    return resultList;
}

3. 單層搜尋(ONELEVEL_SCOPE)

public static List> searchContextOne(DirContext context, String cn,
        String filter, String[] returnedAtts) throws NamingException {
    SearchControls ctls = new SearchControls();
    ctls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
    ctls.setReturningAttributes(returnedAtts);
    // 其餘同 searchContextSub
}

群組成員維護:刪除多值屬性中的特定值

Active Directory 群組成員儲存於 member 或 uniquemember 多值屬性,需移除特定 DN 時:

public static void deleteInAttributes(DirContext ctx, String userDN,
        List attList, String attributeName) throws NamingException {
    if (attList == null || attList.isEmpty()) return;
    int size = attList.size();
    ModificationItem[] mods = new ModificationItem[size];
    for (int i = 0; i < size; i++) {
        mods[i] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE,
                new BasicAttribute(attributeName, attList.get(i)));
    }
    ctx.modifyAttributes(userDN, mods);
}

用法:deleteInAttributes(ctx, "cn=GroupA,ou=Groups,dc=ex,dc=com", dnList, "member") 批次移除群組成員。

整合認證:以使用者憑證驗證 LDAP 登入

public static boolean authenticate(ConfigDto configDto, String uid, char[] password)
        throws NamingException {
    Hashtable env = new Hashtable<>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, configDto.getEnvFactory());
    env.put(Context.PROVIDER_URL, configDto.getEnvUrl());
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.SECURITY_PRINCIPAL,
            Constants.LDAP_PEOPLE_ATTRIBUTE_UID + "=" + uid + "," + configDto.getEnvPeopleLoc());
    env.put(Context.SECURITY_CREDENTIALS, password);

    try {
        new InitialDirContext(env);
        log.debug("User " + uid + " authenticated successfully");
        return true;
    } catch (AuthenticationException ex) {
        log.error("User " + uid + " authentication failed: invalid credentials");
        return false;
    }
}

設計精華:直接嘗試以使用者 DN 建立連線,成功即通過驗證,失敗捕獲 AuthenticationException。無需管理員權限,符合最小權限原則,且自動驗證帳號狀態(鎖定、過期、停用皆會導致綁定失敗)。

關鍵效能與安全提醒

  • 搜尋範圍選擇:SUBTREE 遞歸全樹,資料量大時極慢;精確知道目標層級請用 ONELEVEL 或 OBJECT_SCOPE。
  • 屬性投影:務必使用 setReturningAttributes() 限制網路傳輸與解析開銷。
  • deleteInAttributes 批次操作:單次 modifyAttributes 送出陣列,比迴圈單獨呼叫少 N-1 次網路往返。
  • 認證方法不應記錄密碼明文,char[] 用畢立即清零(此處省略)。

至此核心功能完備,最後一篇將示範完整整合測試案例:建立 AD 使用者、設定屬性、啟用帳號。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved