JAVA使用Ldap操作AD域

早期項目上遇到的需要集成windows域用戶的信息的功能倍试,第一次接觸ad域,因為不了解而且網(wǎng)上其他介紹不明確,比較費時似枕,這里記錄下。

說明:

(1). 特別注意:Java操作查詢域用戶信息獲取到的數(shù)據(jù)和域管理員在電腦上操作查詢的數(shù)據(jù)可能會存在差異(同一個意思的表示字段年柠,兩者可能不同)凿歼。

(2). 連接ad域有兩個地址: ldap://XXXXX.com:389ldap://XXXXX.com:636(SSL)。

(3). 端口389用于一般的連接冗恨,例如登錄答憔,查詢等非密碼操作,端口636安全性較高掀抹,用戶密碼相關操作虐拓,例如修改密碼等。

(4). 域控可能有多臺服務器傲武,之間數(shù)據(jù)同步不及時蓉驹,可能會導致已經(jīng)修改的數(shù)據(jù)被覆蓋掉,這個要么域控縮短同步的時間差揪利,要么同時修改每一臺服務器的數(shù)據(jù)态兴。

1. 389登錄

只要不拋出異常就是驗證通過

public LdapContext adLogin(JSONObject json) {
        String username = json.getString("username");
        String password = json.getString("password");
        String server = "ldap://XXXXXXX.com:389";
        try {
            Hashtable<String, String> env = new Hashtable<String, String>();
            //用戶名稱,cn,ou,dc 分別:用戶疟位,組瞻润,域
            env.put(Context.SECURITY_PRINCIPAL, username);
            //用戶密碼 cn 的密碼
            env.put(Context.SECURITY_CREDENTIALS, password);
            //url 格式:協(xié)議://ip:端口/組,域   ,直接連接到域或者組上面
            env.put(Context.PROVIDER_URL, server);
            //LDAP 工廠
            env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
            //驗證的類型     "none", "simple", "strong"
            env.put(Context.SECURITY_AUTHENTICATION, "simple");
            LdapContext ldapContext = new InitialLdapContext(env, null);
            log.info("ldapContext:" + ldapContext);
            log.info("用戶" + username + "登錄驗證成功");
            return ldapContext;

        } catch (NamingException e) {
            log.info("用戶" + username + "登錄驗證失敗");
            log.info("錯誤信息:"+e.getExplanation());
            return null;
        }
    }

2. 636登錄驗證

證書提前導入的Java庫中 參考:https://www.cnblogs.com/moonson/p/4454159.html

public LdapContext adLoginSSL(JSONObject json) {
String username = json.getString("username");
String password = json.getString("password");
Hashtable env = new Hashtable();

String javaHome = System.getProperty("java.home");
         String keystore = javaHome+"/lib/security/cacerts";
         log.info("java.home,{}",keystore);
    // 加載導入jdk的域證書
         System.setProperty("javax.net.ssl.trustStore", keystore);
         System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
         String LDAP_URL = "ldap://XXXXXX.com:636"; // LDAP訪問地址

         env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
         env.put(Context.SECURITY_PROTOCOL, "ssl");//鏈接認證服務器
         env.put(Context.PROVIDER_URL, LDAP_URL);
         env.put(Context.SECURITY_AUTHENTICATION, "simple");
         env.put(Context.SECURITY_PRINCIPAL, username);
         env.put(Context.SECURITY_CREDENTIALS, password);
         try {
             LdapContext ldapContext = new InitialLdapContext(env, null);
             log.info("認證成功");// 這里可以改成異常拋出。
             return ldapContext;
         } catch (javax.naming.AuthenticationException e) {
             log.info("認證失敗:{}",e.getMessage());
         } catch (Exception e) {
             log.info("認證出錯:{}",e.getMessage());
         }
        return null;
    }

3. 查詢域用戶信息

public List getUserKey(JSONObject json){

 JSONObject admin = new JSONObject();
 admin.put("username","Aaaaa");
 admin.put("password", "bbbbbbbb");
 String name = json.getString("name");
 log.info("需要查詢的ad信息:{}",name);
 List<JSONObject> resultList = new JSONArray();
 LdapContext ldapContext = adLogin(admin); //連接到域控
 if (ldapContext!=null){

 String company = "";
 String result = "";
 try {
 // 域節(jié)點
 String searchBase = "DC=XXXXXXX,DC=com";
 // LDAP搜索過濾器類
 //cn=*name*模糊查詢          //cn=name 精確查詢
          // String searchFilter = "(objectClass="+type+")";
 String searchFilter = "(sAMAccountName="+name+")";    //查詢域帳號

 // 創(chuàng)建搜索控制器
 SearchControls searchCtls = new SearchControls();
 String  returnedAtts[]={"description","sAMAccountName","userAccountControl"};                        searchCtls.setReturningAttributes(returnedAtts); //設置指定返回的字段,不設置則返回全部
 //  設置搜索范圍 深度
 searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
 // 根據(jù)設置的域節(jié)點绍撞、過濾器類和搜索控制器搜索LDAP得到結(jié)果
 NamingEnumeration answer = ldapContext.search(searchBase, searchFilter,searchCtls); 
 // 初始化搜索結(jié)果數(shù)為0
 int totalResults = 0; 
 int rows = 0;
 while (answer.hasMoreElements()) {// 遍歷結(jié)果集
 SearchResult sr = (SearchResult) answer.next();// 得到符合搜索條件的DN
 ++rows;
 String dn = sr.getName();
 log.info(dn);
 Attributes Attrs = sr.getAttributes();// 得到符合條件的屬性集
 if (Attrs != null) {
 try {
 for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore();) {
 Attribute Attr = (Attribute) ne.next();// 得到下一個屬性
 // 讀取屬性值
 for (NamingEnumeration e = Attr.getAll(); e.hasMore(); totalResults++) {
 company = e.next().toString();
 JSONObject tempJson = new JSONObject();

 tempJson.put(Attr.getID(), company.toString());
 resultList.add(tempJson);
 }
 }
 } catch (NamingException e) {
 log.info("Throw Exception : " + e.getMessage());
 }
 } 
 } 
 log.info("總共用戶數(shù):" + rows);
 } catch (NamingException e) {
 log.info("Throw Exception : " + e.getMessage());
 }finally {
 try{
 ldapContext.close();
 }catch (Exception e){
 e.printStackTrace();
 }
 }
 }
 return resultList;
 }

4. 重置用戶密碼

// 管理員重置用戶密碼正勒,后強制用戶首次登錄修改密碼
public Map<String, String> updateAdPwd(JSONObject json) {
 //要修改的帳號(這個dn是查詢的用戶信息里的dn的值,而不是域賬號)
 String dn = json.getString("dn");
 String password = json.getString("password");//新密碼

 JSONObject admin = new JSONObject();
 admin.put("username","aaaaaaa");
 admin.put("password", "bbbbbbb");
 Map<String,String> map = new HashMap<String,String>();
 LdapContext ldapContext = adLoginSSL(admin); //連接636端口域
 ModificationItem[] mods = new ModificationItem[2];
 if (ldapContext!=null){
 try {
 String newQuotedPassword = "\"" + password + "\"";
 byte[] newUnicodePassword = newQuotedPassword.getBytes("UTF-16LE");
// unicodePwd:修改的字段傻铣,newUnicodePassword:修改的值
 mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
 new BasicAttribute("unicodePwd", newUnicodePassword));
mods[1] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
 new BasicAttribute("pwdLastSet", "0"));  // 首次登錄必須修改密碼

 // 修改密碼
 ldapContext.modifyAttributes(dn, mods); 
 map.put("result", "S");
 map.put("message","成功");
 }catch (Exception e){ 
 map.put("result","E");
 map.put("message", "無法重置密碼");
 }finally {
 try{
 ldapContext.close();
 }catch (Exception e){
 e.printStackTrace();
 }

 }

 }else {
 log.info("");
 map.put("result","E");
 map.put("message", "驗證失敗");
 }
 return map;
 }

5. 域賬號解鎖

// 表示鎖定的字段需要測試章贞,不一定這個lockoutTime
public Map<String, String> deblocking(JSONObject json) {
 JSONObject admin = new JSONObject();
 String dn = json.getString("dn"); //被解鎖的帳號(這個dn指的是查詢用戶信息里的dn的值,不是域賬號)
 admin.put("username","aaaaaa");
 admin.put("password","bbbbbb");
 Map<String,String> map = new HashMap<String,String>();
 LdapContext ldapContext = adLogin(admin);
 ModificationItem[] mods = new ModificationItem[1];
 if (ldapContext!=null){
 try {
      // "0" 表示未鎖定非洲,不為0表示鎖定
 mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
 new BasicAttribute("lockoutTime","0"));
 // 解鎖域帳號
 ldapContext.modifyAttributes(dn, mods); 
 map.put("result", "S");
 map.put("message","成功");
 }catch (Exception e){ 
 map.put("result","E");
 map.put("message", "解鎖失敗");
 }finally {
 try{
 ldapContext.close();
 }catch (Exception e){
 e.printStackTrace();
 }
 }
 }else {
 map.put("result","E");
 map.put("message", "驗證失敗");
 }
 return map;
}

公--眾--號:Java質(zhì)變之路

關注獲取更多技能知識(看書太枯燥阱驾,可以先看視頻,之后在看書會容易很多怪蔑,吸收的更多)

1里覆。 關注"Java質(zhì)變之路"之后回復 “技能” 獲取下列技能書籍


技能書籍.png

技能書籍.png

2。 關注"Java質(zhì)變之路"之后回復 “擴展” 獲取下列擴展書籍


擴展書籍.png

3缆瓣。 關注"Java質(zhì)變之路"之后回復 “視頻” 獲取更多視頻


從初級到高手.png
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喧枷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子弓坞,更是在濱河造成了極大的恐慌隧甚,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渡冻,死亡現(xiàn)場離奇詭異戚扳,居然都是意外死亡,警方通過查閱死者的電腦和手機族吻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進店門帽借,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人超歌,你說我怎么就攤上這事砍艾。” “怎么了巍举?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵脆荷,是天一觀的道長。 經(jīng)常有香客問我懊悯,道長蜓谋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任炭分,我火速辦了婚禮桃焕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘欠窒。我一直安慰自己覆旭,他們只是感情好退子,可當我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布岖妄。 她就那樣靜靜地躺著型将,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荐虐。 梳的紋絲不亂的頭發(fā)上七兜,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天,我揣著相機與錄音福扬,去河邊找鬼腕铸。 笑死,一個胖子當著我的面吹牛铛碑,可吹牛的內(nèi)容都是我干的狠裹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼汽烦,長吁一口氣:“原來是場噩夢啊……” “哼涛菠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起撇吞,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤俗冻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后牍颈,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迄薄,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年煮岁,在試婚紗的時候發(fā)現(xiàn)自己被綠了讥蔽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡画机,死狀恐怖勤篮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情色罚,我是刑警寧澤碰缔,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站戳护,受9級特大地震影響金抡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腌且,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一梗肝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铺董,春花似錦巫击、人聲如沸禀晓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽粹懒。三九已至,卻和暖如春顷级,著一層夾襖步出監(jiān)牢的瞬間凫乖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工弓颈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帽芽,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓翔冀,卻偏偏與公主長得像导街,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子纤子,可洞房花燭夜當晚...
    茶點故事閱讀 43,492評論 2 348

推薦閱讀更多精彩內(nèi)容