前言
因文章整体较长,将会拆分为上下两篇在本公众号发出,欢迎大家关注公众号,精彩内容不错过~
JNDI,全称为Java Naming and Directory Interface,是Java提供的一套用于访问命名和目录服务的API。它定义了一组操作,通过这些操作可以在分散的、异构的命名和目录服务中进行名称查找和绑定。
JNDI主要用于在Java应用程序中查找和访问命名服务对象,如数据库连接、JMS队列和主机等。通过JNDI,开发人员可以将应用程序与底层的服务解耦,从而能够更灵活地切换底层服务的实现。
JNDI的核心概念是Context(上下文)。Context是一组名称和对象之间的绑定关系的加权结合,类似于一个键值对的集合。通过Context可以进行名称查找和绑定操作。
JNDI支持多种命名和目录服务提供者,如文件系统、LDAP、CORBA等。开发人员可以根据实际需求选择合适的提供者来访问不同类型的命名和目录服务。
JNDI提供了一种通用的机制,使得Java应用程序可以非常方便地访问和管理各种命名和目录服务,提高了应用程序的灵活性和可扩展性。
一、Naming Service 命名服务
命名服务(Naming Service)是一种用于解决分布式系统中服务发现和服务定位的技术。它充当一个中心化的注册表,用于存储和查询分布式系统中可用的服务的相关信息,如服务名称、IP地址、端口号等。
命名服务可以提供以下功能:
a、服务注册:服务提供者可以将自己的服务注册到命名服务中,包括服务的名称、地址等信息。
b、服务发现:服务消费者可以通过向命名服务查询指定服务的相关信息,从而找到可用的服务提供者。
c、负载均衡:通过命名服务,可以将请求平均分配给多个可用的服务提供者,从而实现负载均衡。
d、容错和弹性:当某个服务提供者宕机或不可用时,命名服务可以自动将请求路由到其他可用的服务提供者,从而实现容错和弹性。
常见的命名服务包括 ZooKeeper、Consul、Eureka 等。它们都提供了简单易用的 API,以便于开发人员在分布式系统中使用命名服务。
二、Directory Service 目录服务
目录服务(Directory Service)是一种用于管理用户、组织和资源的分布式系统。它通常用于存储和提供访问各种信息的目录,包括用户身份、权限、地址、联系方式等。目录服务提供了可靠和高效的数据存储和检索功能,并支持对目录对象进行增删改查的操作。
目录服务的主要功能包括:
用户管理:目录服务可以存储用户的基本信息,如姓名、职位、电话等,并支持用户的认证和授权。它提供了身份验证机制,用于验证用户的身份和访问权限。
组织管理:目录服务可以组织用户和资源,创建和管理组织结构和层级关系。
资源管理:目录服务可以存储和管理各种资源的信息,如服务器、数据库、文件、应用程序等。它提供了简单的接口,用于查询和访问这些资源的相关信息。
访问控制:目录服务可以定义和管理对目录对象和资源的访问权限。管理员可以设置不同用户和组的权限,限制他们对目录和资源的访问。
复制和同步:目录服务通常支持分布式部署,并提供数据的复制和同步功能,以确保数据的可用性和一致性。
LDAP(Lightweight Directory Access Protocol)是目录服务中常用的协议,它定义了客户端与目录服务之间的通信规则和数据格式。常见的目录服务包括 Active Directory、OpenLDAP、Novell eDirectory 等。它们提供了丰富的功能和管理工具,方便开发人员和系统管理员使用目录服务。
三、Reference 引用
在目录服务中,"引用"是指引用其他对象的属性的一种方式。当一个对象引用另一个对象的属性时,它不会复制这些属性的值,而是通过存储一个引用来表示。这样,当被引用的对象的属性发生变化时,引用对象也会相应地反映出这些变化。
在目录服务中,引用可以用于多种场景。例如,一个用户对象可以引用一个组织对象,表示该用户属于这个组织。这样,当组织的属性发生变化时,用户对象中引用的组织对象也会随之更新。
引用的使用可以提高目录服务的灵活性和效率。它可以减少冗余数据的存储,同时保持数据的一致性。此外,引用还可以简化对关联对象的更新和查询操作。
:
Java 技术回顾之 JNDI:命名和目录服务基本概念
https://blog.csdn.net/ericxyy/article/details/2012287
*左右滑动查看更多
四、JNDI目录服务
JNDI(Java Naming and Directory Interface)是Java中用于访问目录和命名服务的API。使用JNDI可以方便地在Java应用程序中访问并管理目录服务。
下面是一个简单的示例代码,演示了如何使用JNDI访问目录服务:
import javax.naming.*;
import javax.naming.directory.*;
public class JNDIExample {
public static void main(String[] args) {
try {
// 创建一个JNDI上下文
Context ctx = new InitialContext();
// 设置目录服务的属性
String url = "ldap://localhost:389"; // 目录服务的URL
String auth = "simple"; // 认证方式,默认为simple
String username = "cn=admin,dc=mydomain,dc=com"; // 认证用户名
String password = "admin123"; // 认证密码
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url);
env.put(Context.SECURITY_AUTHENTICATION, auth);
env.put(Context.SECURITY_PRINCIPAL, username);
env.put(Context.SECURITY_CREDENTIALS, password);
// 连接目录服务
DirContext dirContext = new InitialDirContext(env);
// 在目录服务中创建一个新的条目
Attributes attributes = new BasicAttributes();
attributes.put(new BasicAttribute("cn", "John Doe")); // 设置条目的属性
attributes.put(new BasicAttribute("sn", "Doe"));
attributes.put(new BasicAttribute("mail", "[email protected]"));
dirContext.createSubcontext("cn=John Doe", attributes);
System.out.println("条目创建成功!");
// 关闭连接
dirContext.close();
} catch (NamingException e) {
e.printStackTrace();
}
}
}
*左右滑动查看更多
上面的代码首先创建了一个JNDI上下文,然后设置目录服务的属性,包括目录服务的URL、认证方式、认证用户名和密码。接着,通过调用InitialDirContext类的构造函数连接目录服务。
代码中的createSubcontext方法用于在目录服务中创建一个新的条目,其中cn=John Doe是条目的DN(Distinguished Name),Attributes对象用于设置条目的属性。最后,通过调用close方法关闭连接。
请注意,上述代码中需要将JNDI相关的Jar包加入到项目的Classpath中,例如ldap.jar、jndi.jar等。
这只是一个简单的JNDI目录服务示例,实际使用中可能涉及更多的操作,如查询、更新条目等。您可以根据具体的需求进一步扩展和完善代码。
五、JNDI-DNS 解析
JNDI(Java Naming and Directory Interface)是Java标准库中的API,用于访问命名和目录服务,例如DNS、LDAP(轻量级目录访问协议)等。JNDI提供了一种统一的方式来访问不同类型的命名和目录服务。
在JNDI中使用DNS解析,可以通过以下步骤实现:
1、导入JNDI相关的包:
import javax.naming.*;
import javax.naming.directory.*;
*左右滑动查看更多
2、创建JNDI上下文并设置目录服务属性:
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
env.put(Context.PROVIDER_URL, "dns://your_dns_server_ip");
*左右滑动查看更多
在PROVIDER_URL中填入你的DNS服务器的IP地址。
3、连接到目录服务:
DirContext ctx = new InitialDirContext(env);
*左右滑动查看更多
这里的InitialDirContext类表示初始的上下文对象,用于与目录服务建立连接。
4、进行DNS解析:
Attributes attrs = ctx.getAttributes("your_domain_name", new String[]{"A"});
Attribute attr = attrs.get("A");
if (attr != null) {
for (int i = 0; i < attr.size(); i++) {
System.out.println(attr.get(i));
}
}
*左右滑动查看更多
在ctx.getAttributes方法中,将你想要解析的域名填入your_domain_name中。new String[]{"A"}表示只获取A记录。
5、关闭连接:
ctx.close();
在完成后关闭JNDI上下文以释放资源。
以上是一个简单的使用JNDI进行DNS解析的代码示例。你可以根据自己的需求进行修改和扩展。
六、JNDI-RMI 远程方法调用
JNDI(Java Naming and Directory Interface)是Java提供的一组API,用于与各种命名和目录服务进行交互。JNDI-RMI是JNDI中的一种功能,用于进行远程方法调用(Remote Method Invocation,简称RMI)。
下面是一个简单的Java代码示例,演示如何使用JNDI-RMI进行远程方法调用:
import javax.naming.Context;
import javax.naming.InitialContext;
import java.rmi.Remote;
public class RmiClient {
public static void main(String[] args) {
try {
// 创建JNDI上下文
Context context = new InitialContext();
// 设置目标RMI服务器的URL
String rmiUrl = "rmi://localhost:1234/Server";
// 通过JNDI查找远程对象
Remote remote = (Remote) context.lookup(rmiUrl);
// 调用远程对象的方法
// ...
// 关闭JNDI上下文
context.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
*左右滑动查看更多
以上代码示例中,我们首先创建了一个JNDI上下文(Context),然后设置了RMI服务器的URL(rmi://localhost:1234/Server)。
接下来,我们通过调用context.lookup()方法来查找指定URL对应的远程对象。返回的对象需要进行类型转换为远程接口(Remote)类型。
最后,我们就可以像调用本地对象一样,通过调用远程对象的方法来实现远程方法调用。
请注意,上述代码示例中使用的URL(rmi://localhost:1234/Server)是示例URL,实际上应该替换为您要连接的RMI服务器的URL。
七、JNDI-LDAP
JNDI-LDAP(Java Naming and Directory Interface-Lightweight Directory Access Protocol)是用于访问LDAP(Lightweight Directory Access Protocol)服务器的Java API。使用JNDI-LDAP,您可以连接到LDAP服务器并执行各种操作,包括搜索、添加、修改和删除条目。
这里给出了一个简单的Java代码示例来说明如何使用JNDI-LDAP进行LDAP操作:
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
public class LDAPExample {
public static void main(String[] args) {
try {
// 创建JNDI上下文
Context ctx = new InitialContext();
// 设置LDAP服务器URL
String ldapServerUrl = "ldap://localhost:389";
// 创建LDAP连接
DirContext ldapContext = (DirContext) ctx.lookup(ldapServerUrl);
// 设置搜索控制器
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// 设置搜索过滤条件和搜索基准
String searchFilter = "(objectClass=inetOrgPerson)";
String searchBase = "dc=mydomain,dc=com";
// 执行搜索
NamingEnumeration<SearchResult> searchResults = ldapContext.search(searchBase, searchFilter, searchControls);
// 遍历搜索结果
while (searchResults.hasMore()) {
SearchResult searchResult = searchResults.next();
Attributes attributes = searchResult.getAttributes();
// 处理搜索结果
// ...
}
// 关闭LDAP连接
ldapContext.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
*左右滑动查看更多
这段代码首先创建了一个JNDI上下文,并设置了LDAP服务器的URL。
然后,它创建了一个LDAP连接,并设置了搜索控制器,以指定搜索的范围、过滤条件和搜索基准。
接下来,它执行搜索操作,并遍历搜索结果。
最后,它关闭了LDAP连接。
八、JNDI-DataSource
JNDI-DataSource 是一种使用 JNDI(Java Naming and Directory Interface)来管理数据库连接池的技术。它可以帮助我们简化数据库连接的管理,并提高性能和可扩展性。
下面是一个使用 JNDI-DataSource 的 Java 代码示例:
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JNDIDataSourceExample {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 获取 JNDI 上下文
Context context = new InitialContext();
// 查找 DataSource
DataSource dataSource = (DataSource) context.lookup("java:comp/env/jdbc/myDataSource");
// 从 DataSource 获取连接
connection = dataSource.getConnection();
// 创建 Statement
statement = connection.createStatement();
// 执行 SQL 查询
resultSet = statement.executeQuery("SELECT * FROM users");
// 处理查询结果
while (resultSet.next()) {
String username = resultSet.getString("username");
String email = resultSet.getString("email");
System.out.println("Username: " + username + ", Email: " + email);
}
} catch (NamingException | SQLException e) {
e.printStackTrace();
} finally {
// 关闭资源
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
*左右滑动查看更多
在这段代码中,我们首先使用 InitialContext 类获取 JNDI 上下文。
然后,我们使用 lookup 方法在上下文中查找 DataSource 对象。
java:comp/env/jdbc/myDataSource 是一个示例数据源的 JNDI 名称,你可以根据你的具体配置进行修改。
接下来,我们使用 getConnection 方法从 DataSource 获取一个数据库连接。然后,我们创建 Statement 对象并执行 SQL 查询。
最后,我们处理查询结果并关闭相关资源。
需要注意的是,这段代码还涉及一些异常处理和资源关闭的逻辑,确保在使用完资源后正确地释放它们。
九、JNDI-协议转换
如果 JNDI 在 lookup 时没有指定初始化工厂名称,会自动根据协议类型动态查找内置的工厂类然后创建处理对应的服务请求。
JNDI 默认支持自动转换的协议有:
协议名称 | 协议 URL | Context 类 |
---|---|---|
DNS 协议 | dns:// |
com.sun.jndi.url.dns.dnsURLContext |
RMI 协议 | rmi:// |
com.sun.jndi.url.rmi.rmiURLContext |
LDAP 协议 | ldap:// |
com.sun.jndi.url.ldap.ldapURLContext |
LDAP 协议 | ldaps:// |
com.sun.jndi.url.ldaps.ldapsURLContextFactory |
IIOP 对象请求代理协议 | iiop:// |
com.sun.jndi.url.iiop.iiopURLContext |
IIOP 对象请求代理协议 | iiopname:// |
|
com.sun.jndi.url.iiopname.iiopnameURLContextFactory |
||
IIOP 对象请求代理协议 | corbaname:// |
|
com.sun.jndi.url.corbaname.corbanameURLContextFactory |
*左右滑动查看更多
十、JNDI-Reference
JNDI(Java命名与目录接口)是Java EE平台中用于访问命名和目录服务的API。JNDI提供了从一个上下文对象中查找其他Java对象的机制。JNDI-Reference是JNDI API中的一种数据对象,它可以包含对其他对象的引用。
下面是一个使用JNDI-Reference的简单Java代码示例:
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class JNDIReferenceExample {
public static void main(String[] args) {
try {
// 创建一个JNDI上下文对象
Context context = new InitialContext();
// 通过JNDI上下文对象查找一个JNDI-Reference对象
MyReferenceObject referenceObject = (MyReferenceObject) context.lookup("java:comp/env/myReferenceObject");
// 使用JNDI-Reference对象中的方法或属性
referenceObject.doSomething();
} catch (NamingException e) {
e.printStackTrace();
}
}
}
*左右滑动查看更多
在这个示例中,我们首先创建了一个JNDI上下文对象Context,这个对象是使用JNDI API中的InitialContext类来创建的。
然后,我们使用JNDI上下文对象的lookup方法来查找名为"java:comp/env/myReferenceObject"的JNDI-Reference对象。这里的"java:comp/env"是JNDI命名空间的一个默认前缀,可以用于访问应用程序的环境配置信息。
如果找到了名为
"java:comp/env/myReferenceObject"的JNDI-Reference对象,我们将其转换为MyReferenceObject类型,并可以使用该对象中的方法或属性。
需要注意的是,这个示例代码只是演示了如何使用JNDI-Reference对象,真实的JNDI-Reference对象的使用可能会涉及更复杂的配置和上下文设置。
(未完待续)
原文始发于微信公众号(安恒信息安全服务):九维团队-绿队(改进)| JNDI用法示例及安全开发建议(上)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论