本篇没有太多主观内容,网摘为主,有少部分个人补充。
首先是 VSC 上的 Java 环境搭建,来自 https://www.cnblogs.com/asminfo/p/11096681.html,由于本人有排版洁癖,故而也原文转录于此。
Visual Studio Code 上 Java 开发环境搭建
在把一些开源的 SDK 中 Java 代码转成 C# 代码时经常需要写点 Java 代码来实验下功能,装个 Eclipse 或 IDEAs 吧,好像也不太值当,所以用 Visual Studio Code 搭个环境偶尔来实验下。
1. 下载并装好 Java SDK,设置环境变量:JAVA_HOME,PATH,CLASSPATH(验证:java -version);
2. 下载并安装 maven。设好环境变量:PATH(验证:mvn -v);
3. 安装 Visual Studio Code 插件,有:
– Language Support for Java(TM) by RedHat:通过 Eclipse™ JDT Language Server 提供 Java 语言支持;
– Debugger for Java:基于 Java Debug Server 的轻量级调试工具;
– Java Test Runner:执行和调试 Java 测试用例;
– Maven for Java:Maven 插件。
4. 创建 maven 项目:
– 按下 Ctrl+Shift+P 打开命令面板,执行 Generate from Maven Archetype 命令;
– 在弹出的对话框中选择一个生成项目的目录,接着选择基于 maven-archetype-quickstart 创建;
– 选择完成后,会开始项目的生成,期间需要在终端中填入必要的信息:groupId(组织名),artifactId(项目名),version(版本号),package(打包后 jar 的名称);
– 创建完成后,打开目录即可。
5. 调试。Ctrl+Shift+D 可打开调试面板,进行调试。
其次是对于 LDAP 的简介,来自 https://www.cnblogs.com/lxlovezhd/archive/2013/05/29/3105350.html。
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 是树状的,用节点来存放数据。一个树枝可以有 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)和多个值(Value)组成,类似于关系数据库中的域(Field)由域名和数据类型组成。为了方便检索的需要,LDAP 中的 Type 可以有多个 Value,而不是关系数据库中为降低数据的冗余性要求实现的各个域必须是不相关的。LDAP 中条目的组织一般按照地理位置和组织关系进行组织,非常直观。LDAP 把数据存放在文件中,为提高效率可以使用基于索引的文件数据库,而不是关系数据库。LDAP 协议集还规定了 DN 的命名方法、存取控制方法、搜索格式、复制方法、URL 格式、开发接口等。LDAP 对于这样存储这样的信息最为有用,也就是:数据需要从不同的地点读取,但是不需要经常更新。
常见的属性(Attribute)有:
关键字 说明 dc 域名。其格式是将完整的域名分成几部分,如域名为 example.com,变成 dc=example, dc=com uid 用户 ID。如“kelly” ou 组织机构。类似于 Linux 文件系统中的子目录,是个容器对象。组织机构可以包含其他各种对象(包括其他组织机构),如“sales” cn 全称。如“Kelly King” sn 姓。 如“King” dn 唯一标识。类似于 Linux 文件系统中的绝对路径,每个对象都有一个唯一的名称,如 “uid=kelly,ou=sales,dc=example,dc=com”,在一个目录树中 DN 总是唯一的 rdn 相对唯一标识。类似于文件系统中的相对路径,它是与目录树结构无关的部分。如“uid=kelly”或“cn=Kelly King” c 国家。如“CN”或“US”等 o 组织名称。如“Example, Inc.”
再次,是 Java 写的进行 LDAP 认证的代码,此代码时间上 https://www.iteye.com/blog/samjavaeye-1607653 为早,但上面的 LDAP 介绍网页内也有,只是有非常轻微的不同。代码中,验证了我上一篇博文的一个猜想,那就是可以用搜索的方式去认证一个用户,主要是为了应对 RDN 可能是 uid 或者 cn 带来的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
public class LDAPAuthentication { private final String URL = "ldap://ldapserver:389/"; private final String BASEDN = "ou=people,o=xxx.com.cn"; 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"); // 此处若不指定用户名和密码则自动转换为匿名登录 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 valid = 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 + " 验证通过"); valid = true; } catch (AuthenticationException e) { System.out.println(userDN + " 验证失败"); System.out.println(e.toString()); valid = false; } catch (NamingException e) { System.out.println(userDN + " 验证失败"); valid = false; } return valid; } public static void main(String[] args) { String uid = "username", password = "password"; LDAPAuthentication _this = new LDAPAuthentication(); _this.authenricate(uid, password); } } |
最后,是 Java 代码写就的其他一些对 LDAP 的操作,来自 https://www.cnblogs.com/adam1991/p/7656415.html,备今后可能使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
// 1. Connect LDAP public DirContext createDirContext(String ip, int port, String bindDn, String password) { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://" + ip + ":" + port); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, bindDn); env.put(Context.SECURITY_CREDENTIALS, password); DirContext ctx = null; try { ctx = new InitialDirContext(env); } catch (NamingException e) { e.printStackTrace(); } return ctx; } // 2. Add item public void addItem(String ip, int port, String bindDN, String password, String itemDn, HashMap<String, ArrayList<String>> attrValueMap) throws NamingException { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://" + ip + ":" + port); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, bindDN); env.put(Context.SECURITY_CREDENTIALS, password); DirContext ctx = null; try { ctx = new InitialDirContext(env); BasicAttributes entry = new BasicAttributes(true); Iterator<String> defaultAttrValueMapKeyIt = attrValueMap.keySet().iterator(); while (defaultAttrValueMapKeyIt.hasNext()) { String attr = defaultAttrValueMapKeyIt.next(); ArrayList<String> valueList = attrValueMap.get(attr); if (1 == valueList.size()) { entry.put(attr, valueList.get(0)); } else { Attribute attribute = new BasicAttribute(attr); for (String value : valueList) { attribute.add(value); } entry.put(attribute); } } ctx.createSubcontext(itemDn, entry); } catch (NamingException e) { throw e; } finally { ctx.close(); } } // 3. Update item public void updateUser(String ip, int port, String bindDN, String password, String itemDn, HashMap<String, ModifyAttribute> modifyAttrMap) throws NamingException { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://" + ip + ":" + port); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, bindDn); env.put(Context.SECURITY_CREDENTIALS, password); DirContext ctx = null; try { ctx = new InitialDirContext(env); ModificationItem[] modificationItems = new ModificationItem[modifyAttrMap.size()]; int i = 0; Iterator<String> it = modifyAttrMap.keySet().iterator(); while (it.hasNext()) { ModifyAttribute ma = modifyAttrMap.get(it.next()); modificationItems[i++] = new ModificationItem(ma.getType(), new BasicAttribute(ma.getAttr(), ma.getValue())); } ctx.modifyAttributes(itemDn, modificationItems); } catch (NamingException e) { throw e; } finally { ctx.close(); } } // 4. Delete item public void deleteUser(String ip, int port, String bindDn, String password, String itemDn) throws NamingException { if (null != itemDn && !itemDn.equals("")) { Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://" + ip + ":" + port); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, bindDn); env.put(Context.SECURITY_CREDENTIALS, password); DirContext ctx = null; try { ctx = new InitialDirContext(env); ctx.destroySubcontext(itemDn); } catch (NamingException e) { throw e; } finally { ctx.close(); } } } |