早期項目上遇到的需要集成windows域用戶的信息的功能倍试,第一次接觸ad域,因為不了解而且網(wǎng)上其他介紹不明確,比較費時似枕,這里記錄下。
說明:
(1). 特別注意:Java操作查詢域用戶信息獲取到的數(shù)據(jù)和域管理員在電腦上操作查詢的數(shù)據(jù)可能會存在差異(同一個意思的表示字段年柠,兩者可能不同)凿歼。
(2). 連接ad域有兩個地址: ldap://XXXXX.com:389 和 ldap://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ì)變之路"之后回復 “技能” 獲取下列技能書籍
2。 關注"Java質(zhì)變之路"之后回復 “擴展” 獲取下列擴展書籍
3缆瓣。 關注"Java質(zhì)變之路"之后回復 “視頻” 獲取更多視頻