Java程序通過LDAP對用戶進行登陸驗證

       在去年南京項目中,客戶方要求用戶登陸需要在其他平臺下進行認證,當時客戶用的LDAP“數據庫”管理方式,後來查閱Java已經對LDAP進行了封裝,不需要下載其他jar包就可以實現。

       補腦:【LDAP】是"Lightweight Directory Access Protocol"的縮寫,中文翻譯過來就叫“輕量目錄訪問協議”,看字面大概能猜出應該是以樹狀形存儲數據的數據庫,後來翻閱資料確實如此。其中包含幾個重要的參數:CN,DN,DC,OU。至於這個縮寫單詞的含義,有興趣可以去百科或者官網腦補一下,下面程序中將會引用這幾個才參數,也會進行簡單的描述。

package com.angma.mes.zbe.moudle.service.util;

import com.angma.mes.jagybarcode.manager.controller.plan.machine.MachineShopTaskCreateController;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

/**
 * 用戶登陸認證,LDAP跨域認證,通過LDAP對用戶進行更新
 * 
 * @author xlj
 * @date 2015.07.10
 */
public class LdapUtil {

	private static DirContext ctx;

	// LDAP服務器端口默認爲389
	private static final String LDAP_URL = "ldap://127.0.0.1:389";

	// ROOT根據此參數確認用戶組織所在位置
	private static final String LDAP_PRINCIPAL = "OU=CMA Users,DC=changan-mazda,DC=com,DC=cn";

	// LDAP驅動
	private static final String LDAP_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";

	private static Logger logger = Logger.getLogger(LdapUtil.class);

	/**** 測試 ****/
	public static void main(String[] args) {
		LdapUtil.getLoginContext();
		LdapUtil.addUserLdap("10000", "123456");
		LdapUtil.updatePasswordLdap("10000", "1234567");
		LdapUtil.deleteUserLdap("10000");
	}

	// 通過連接LDAP服務器對用戶進行認證,返回LDAP對象
	public static DirContext getLoginContext() {
		String account = "zhangsan"; // 模擬用戶名
		String password = "123456"; // 模擬密碼
		for (int i = 0; i < 5; i++) { // 驗證次數
			Hashtable env = new Hashtable();
			env.put(Context.SECURITY_AUTHENTICATION, "simple");
			env.put(Context.SECURITY_CREDENTIALS, password);
			// cn=屬於哪個組織結構名稱,ou=某個組織結構名稱下等級位置編號
			env.put(Context.SECURITY_PRINCIPAL, "cn=" + account + ", ou=Level0" + i + "00," + LDAP_URL);
			env.put(Context.INITIAL_CONTEXT_FACTORY, LDAP_PRINCIPAL);
			env.put(Context.PROVIDER_URL, LDAP_FACTORY);
			try {
				// 連接LDAP進行認證
				ctx = new InitialDirContext(env);
				System.out.println("認證成功");
				logger.info("【" + account + "】用戶於【" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "】登陸系統成功");
			} catch (javax.naming.AuthenticationException e) {
				System.out.println("認證失敗");
			} catch (NamingException err) {
				logger.info("--------->>【" + account + "】用戶驗證失敗【" + i + "】次");
			} catch (Exception e) {
				System.out.println("認證出錯:");
				e.printStackTrace();
			}
		}
		return ctx;
	}

	// 將輸入用戶和密碼進行加密算法後驗證
	public static boolean verifySHA(String ldappw, String inputpw) {

		// MessageDigest 提供了消息摘要算法,如 MD5 或 SHA,的功能,這裏LDAP使用的是SHA-1
		MessageDigest md = MessageDigest.getInstance("SHA-1");

		// 取出加密字符
		if (ldappw.startsWith("{SSHA}")) {
			ldappw = ldappw.substring(6);
		} else if (ldappw.startsWith("{SHA}")) {
			ldappw = ldappw.substring(5);
		}

		// 解碼BASE64
		byte[] ldappwbyte = Base64.decode(ldappw);
		byte[] shacode;
		byte[] salt;

		// 前20位是SHA-1加密段,20位後是最初加密時的隨機明文
		if (ldappwbyte.length <= 20) {
			shacode = ldappwbyte;
			salt = new byte[0];
		} else {
			shacode = new byte[20];
			salt = new byte[ldappwbyte.length - 20];
			System.arraycopy(ldappwbyte, 0, shacode, 0, 20);
			System.arraycopy(ldappwbyte, 20, salt, 0, salt.length);
		}

		// 把用戶輸入的密碼添加到摘要計算信息
		md.update(inputpw.getBytes());
		// 把隨機明文添加到摘要計算信息
		md.update(salt);

		// 按SSHA把當前用戶密碼進行計算
		byte[] inputpwbyte = md.digest();

		// 返回校驗結果
		return MessageDigest.isEqual(shacode, inputpwbyte);
	}

	// 添加用戶
	public static boolean addUserLdap(String account, String password) {
		boolean success = false;
		try {
			ctx = LdapUtil.getLoginContext();
			BasicAttributes attrsbu = new BasicAttributes();
			BasicAttribute objclassSet = new BasicAttribute("objectclass");
			objclassSet.add("person");
			objclassSet.add("top");
			objclassSet.add("organizationalPerson");
			objclassSet.add("inetOrgPerson");
			attrsbu.put(objclassSet);
			attrsbu.put("sn", account);
			attrsbu.put("uid", account);
			attrsbu.put("userPassword", password);
			ctx.createSubcontext("cn=" + account + ",ou=People", attrsbu);
			ctx.close();
			return true;
		} catch (NamingException ex) {
			try {
				if (ctx != null) {
					ctx.close();
				}
			} catch (NamingException namingException) {
				namingException.printStackTrace();
			}
			logger.info("--------->>添加用戶失敗");
		}
		return false;
	}

	// 修改密碼
	public static boolean updatePasswordLdap(String account, String password) {
		boolean success = false;
		try {
			ctx = LdapUtil.getLoginContext();
			ModificationItem[] modificationItem = new ModificationItem[1];
			modificationItem[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userPassword", password));
			ctx.modifyAttributes("cn=" + account + ",ou=People", modificationItem);
			ctx.close();
			return true;
		} catch (NamingException ex) {
			try {
				if (ctx != null) {
					ctx.close();
				}
			} catch (NamingException namingException) {
				namingException.printStackTrace();
			}
			logger.info("--------->>修改密碼失敗");
		}
		return success;
	}

	// 刪除用戶
	public static boolean deleteUserLdap(String account) {
		try {
			ctx = LdapUtil.getLoginContext();
			ctx.destroySubcontext("cn=" + account);
		} catch (Exception ex) {
			try {
				if (ctx != null) {
					ctx.close();
				}
			} catch (NamingException namingException) {
				namingException.printStackTrace();
			}
			logger.info("--------->>刪除用戶失敗");
			return false;
		}
		return true;
	}

	// 關閉LDAP服務器連接
	public static void closeCtx() {
		try {
			ctx.close();
		} catch (NamingException ex) {
			logger.info("--------->> 關閉LDAP連接失敗");
		}
	}
}

聲明:以上教程爲博主原創,若需轉載請註明出處,謝謝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章