高级连接信息
连接协议和安全性
驱动程序和服务器之间的通信由 Bolt 介导。服务器 URI 的方案决定了连接是否加密,如果加密,则决定接受哪种类型的证书。
URL 方案 | 加密 | 备注 |
---|---|---|
neo4j |
本地设置的默认值 |
|
neo4j+s |
(仅限 CA 签名证书) |
Aura 的默认值 |
neo4j+ssc |
(CA 和自签名证书) |
无论实例是真正的集群环境还是单机环境,驱动程序在成功连接后都会从服务器接收到路由表。驱动程序的路由行为与Neo4j 的集群协同工作,将读/写事务定向到适当的集群成员。如果您想定位特定机器,请改用 bolt 、bolt+s 或 bolt+ssc URI 方案。 |
要使用的连接方案不是由您选择的,而是由服务器要求决定的。您必须事先知道正确的服务器方案,因为在连接之前不会暴露任何元数据。如果您不确定,请咨询数据库管理员。
身份验证方法
基本身份验证(默认)
基本身份验证方案依赖于传统的用户名和密码。这些可以是您本地安装的凭据,也可以是 Aura 实例提供的凭据。
// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.GraphDatabase;
GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword));
基本身份验证方案也可用于针对 LDAP 服务器进行身份验证(仅限企业版)。
Kerberos 身份验证
Kerberos 身份验证方案需要 base64 编码的票据。它只能在服务器安装了Kerberos 附加组件的情况下使用。
// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.GraphDatabase;
GraphDatabase.driver(dbUri, AuthTokens.kerberos(ticket));
Bearer 身份验证
Bearer 身份验证方案需要由身份提供者通过 Neo4j 的单点登录功能提供的 base64 编码令牌。
// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.GraphDatabase;
GraphDatabase.driver(dbUri, AuthTokens.bearer(ticket));
Bearer 身份验证方案要求在服务器上配置单点登录。一旦配置完成,客户端可以通过发现 API 发现 Neo4j 的配置。 |
自定义身份验证
使用 AuthTokens.custom()
登录到具有自定义身份验证方案的服务器。
// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.GraphDatabase;
GraphDatabase.driver(dbUri, AuthTokens.custom(principal, credentials, realm, scheme, parameters));
轮换身份验证令牌
可以轮换预期会过期的身份验证令牌(例如 SSO)。在实例化 Driver
时,您需要提供一个 AuthTokenManager
实例,而不是静态身份验证令牌。
最简单的入门方法是使用内置的 AuthTokenManager
实现之一。AuthTokenManagers 与 AuthToken
对象配合使用。
// import java.time.Clock;
// import java.util.concurrent.TimeUnit;
// import org.neo4j.driver.AuthTokenManagers;
// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.GraphDatabase;
void rotatingBearerDriver() {
var tokenManager = AuthTokenManagers.bearer(() -> {
var token = AuthTokens.bearer(getToken());
// Assume we know tokens expire every 60 seconds
var expiresIn = TimeUnit.SECONDS.toMillis(60);
// Include a little buffer so that new token is fetched before the old one expires
var expiration = Clock.systemUTC().millis() + (expiresIn - TimeUnit.SECONDS.toMillis(10));
return token.expiringAt(expiration);
});
var driver = GraphDatabase.driver(dbUri, tokenManager);
}
// Some way to get a token
private String getToken() {
return "token-string";
}
AuthTokenManager 对象不得以任何方式与驱动程序交互,因为这可能导致死锁和未定义行为。 |
双向 TLS(客户端证书作为第二因素)
双向 TLS (mTLS) 允许您使用客户端证书作为与服务器进行身份验证的第二因素。证书只能与身份验证令牌一起使用,除非服务器上禁用了身份验证,否则它不能替代常规身份验证。
客户端的证书和公钥必须放置在服务器的 <NEO4J_HOME>/certificates/bolt/trusted
目录中。有关服务器设置的更多信息,请参阅配置通过 Bolt 的 SSL。
要使 mTLS 工作,驱动程序与服务器的连接必须加密,即连接 URI 方案必须是 +s 或 +ssc (例如 neo4j+s://example.com:7687 )。 |
对于静态和轮换证书,都使用 ClientCertificateManagers.rotating()
。
该方法接受一个 ClientCertificate
实例。
对于轮换证书,使用 .rotate()
方法;静态证书无需更新。
var certificateFile = new File("/path/to/cert.pem");
var privateKeyFile = new File("/path/to/key.pem");
var keyPassword = "password"; // optional
var certificate = ClientCertificates.of(certificateFile, privateKeyFile, keyPassword);
var certificateManager = ClientCertificateManagers.rotating(certificate);
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword), certificateManager)) {
// use the driver
}
var certificateFile = new File("/path/to/cert.pem");
var privateKeyFile = new File("/path/to/key.pem");
var keyPassword = "password"; // optional
var certificate = ClientCertificates.of(certificateFile, privateKeyFile, keyPassword);
// instantiate the rotating certificate with an initial one
var certificateManager = ClientCertificateManagers.rotating(certificate);
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword), certificateManager)) {
// use the driver...
// ... until it's time to rotate the certificate
var updatedCertificate = ClientCertificates.of(
new File("/path/to/new/cert.pem")
new File("/path/to/new/key.pem"),
"newPassword" // optional
);
certificateManager.rotate(updatedCertificate);
// use the driver some more - new connections are opened with the new certificate
}
日志记录
默认情况下,驱动程序通过 Java 日志框架 java.util.logging
记录 INFO
消息。要更改驱动程序的日志记录行为,请在创建 Driver
对象时使用 .withLogging()
方法。
// import java.util.logging.Level;
// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.Config;
// import org.neo4j.driver.GraphDatabase;
// import org.neo4j.driver.Logging;
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword),
Config.builder().withLogging(Logging.console(Level.FINE)).build())) {
driver.verifyConnectivity();
}
2023-12-22T10:36:39.997882867 INFO org.neo4j.driver.internal.DriverFactory - Routing driver instance 1651855867 created for server address localhost:7687
2023-12-22T10:36:40.03430944 FINE io.netty.channel.DefaultChannelId - -Dio.netty.processId: 23665 (auto-detected)
2023-12-22T10:36:40.036871656 FINE io.netty.util.NetUtil - -Djava.net.preferIPv4Stack: false
2023-12-22T10:36:40.037023871 FINE io.netty.util.NetUtil - -Djava.net.preferIPv6Addresses: false
2023-12-22T10:36:40.03827624 FINE io.netty.util.NetUtilInitializations - Loopback interface: lo (lo, 0:0:0:0:0:0:0:1%lo)
2023-12-22T10:36:40.038877108 FINE io.netty.util.NetUtil - /proc/sys/net/core/somaxconn: 4096
2023-12-22T10:36:40.03958947 FINE io.netty.channel.DefaultChannelId - -Dio.netty.machineId: 04:cf:4b:ff:fe:0e:ee:99 (auto-detected)
2023-12-22T10:36:40.04531968 FINE io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.level: simple
2023-12-22T10:36:40.045471749 FINE io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.targetRecords: 4
2023-12-22T10:36:40.059848221 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numHeapArenas: 40
2023-12-22T10:36:40.060000842 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.numDirectArenas: 40
2023-12-22T10:36:40.060113675 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.pageSize: 8192
2023-12-22T10:36:40.060219802 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxOrder: 9
2023-12-22T10:36:40.060324679 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.chunkSize: 4194304
2023-12-22T10:36:40.060442554 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.smallCacheSize: 256
2023-12-22T10:36:40.060547232 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.normalCacheSize: 64
2023-12-22T10:36:40.060648929 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedBufferCapacity: 32768
2023-12-22T10:36:40.060750268 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimInterval: 8192
2023-12-22T10:36:40.060858214 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.cacheTrimIntervalMillis: 0
2023-12-22T10:36:40.060965492 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.useCacheForAllThreads: false
2023-12-22T10:36:40.061068878 FINE io.netty.buffer.PooledByteBufAllocator - -Dio.netty.allocator.maxCachedByteBuffersPerChunk: 1023
2023-12-22T10:36:40.069792775 FINE io.netty.buffer.ByteBufUtil - -Dio.netty.allocator.type: pooled
2023-12-22T10:36:40.069957048 FINE io.netty.buffer.ByteBufUtil - -Dio.netty.threadLocalDirectBufferSize: 0
2023-12-22T10:36:40.070070891 FINE io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
2023-12-22T10:36:40.102235419 FINE io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.checkAccessible: true
2023-12-22T10:36:40.102408774 FINE io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.checkBounds: true
2023-12-22T10:36:40.103026138 FINE io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@1a67b908
2023-12-22T10:36:40.104721387 FINE org.neo4j.driver.internal.async.connection.ChannelConnectedListener - [0xb354eed2][localhost(127.0.0.1):7687][] C: [Bolt Handshake] [0x6060b017, 263173, 132100, 260, 3]
2023-12-22T10:36:40.106645202 FINE io.netty.util.Recycler - -Dio.netty.recycler.maxCapacityPerThread: 4096
2023-12-22T10:36:40.106785483 FINE io.netty.util.Recycler - -Dio.netty.recycler.ratio: 8
2023-12-22T10:36:40.106887674 FINE io.netty.util.Recycler - -Dio.netty.recycler.chunkSize: 32
2023-12-22T10:36:40.106993748 FINE io.netty.util.Recycler - -Dio.netty.recycler.blocking: false
2023-12-22T10:36:40.107096042 FINE io.netty.util.Recycler - -Dio.netty.recycler.batchFastThreadLocalOnly: true
2023-12-22T10:36:40.11603651 FINE org.neo4j.driver.internal.async.connection.HandshakeHandler - [0xb354eed2][localhost(127.0.0.1):7687][] S: [Bolt Handshake] 5.4
2023-12-22T10:36:40.128082306 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][] C: HELLO {routing={address: "localhost:7687"}, bolt_agent={product: "neo4j-java/dev", language: "Java/17.0.9", language_details: "Optional[Eclipse Adoptium; OpenJDK 64-Bit Server VM; 17.0.9+9]", platform: "Linux; 5.15.0-91-generic; amd64"}, user_agent="neo4j-java/dev"}
2023-12-22T10:36:40.130350166 FINE org.neo4j.driver.internal.async.pool.NettyChannelTracker - Channel [0xb354eed2] created. Local address: /127.0.0.1:32794, remote address: /127.0.0.1:7687
2023-12-22T10:36:40.130746872 FINE org.neo4j.driver.internal.async.pool.NettyChannelTracker - Channel [0xb354eed2] acquired from the pool. Local address: /127.0.0.1:32794, remote address: /127.0.0.1:7687
2023-12-22T10:36:40.133652153 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][] C: LOGON {principal="neo4j", scheme="basic", credentials="******"}
2023-12-22T10:36:40.140017819 FINE org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher - [0xb354eed2][localhost(127.0.0.1):7687][] S: SUCCESS {server="Neo4j/5.16.0", connection_id="bolt-5", hints={connection.recv_timeout_seconds: 120}}
2023-12-22T10:36:40.142229689 FINE org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] S: SUCCESS {}
2023-12-22T10:36:40.14568667 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] C: RESET
2023-12-22T10:36:40.146897982 FINE org.neo4j.driver.internal.async.NetworkConnection - Added ConnectionReadTimeoutHandler
2023-12-22T10:36:40.14753571 FINE org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] S: SUCCESS {}
2023-12-22T10:36:40.147813446 FINE org.neo4j.driver.internal.async.NetworkConnection - Removed ConnectionReadTimeoutHandler
2023-12-22T10:36:40.14895232 FINE org.neo4j.driver.internal.async.pool.NettyChannelTracker - Channel [0xb354eed2] released back to the pool
2023-12-22T10:36:40.15199869 FINE org.neo4j.driver.internal.cluster.RoutingTableRegistryImpl - Routing table handler for database 'system' is added.
2023-12-22T10:36:40.152613749 FINE org.neo4j.driver.internal.cluster.RoutingTableHandlerImpl - Routing table for database 'system' is stale. Ttl 1703237800150, currentTime 1703237800152, routers [], writers [], readers [], database 'system'
2023-12-22T10:36:40.159510973 FINE org.neo4j.driver.internal.async.pool.NettyChannelTracker - Channel [0xb354eed2] acquired from the pool. Local address: /127.0.0.1:32794, remote address: /127.0.0.1:7687
2023-12-22T10:36:40.165704119 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] C: ROUTE {address="localhost:7687"} [] system null
2023-12-22T10:36:40.168929698 FINE org.neo4j.driver.internal.async.NetworkConnection - Added ConnectionReadTimeoutHandler
2023-12-22T10:36:40.171700427 FINE org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] S: SUCCESS {rt={servers: [{addresses: ["localhost:7687"], role: "WRITE"}, {addresses: ["localhost:7687"], role: "READ"}, {addresses: ["localhost:7687"], role: "ROUTE"}], ttl: 300, db: "system"}}
2023-12-22T10:36:40.17187084 FINE org.neo4j.driver.internal.async.NetworkConnection - Removed ConnectionReadTimeoutHandler
2023-12-22T10:36:40.173921853 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] C: RESET
2023-12-22T10:36:40.174473474 FINE org.neo4j.driver.internal.async.NetworkConnection - Added ConnectionReadTimeoutHandler
2023-12-22T10:36:40.175516332 FINE org.neo4j.driver.internal.async.inbound.InboundMessageDispatcher - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] S: SUCCESS {}
2023-12-22T10:36:40.175679271 FINE org.neo4j.driver.internal.async.NetworkConnection - Removed ConnectionReadTimeoutHandler
2023-12-22T10:36:40.175849144 FINE org.neo4j.driver.internal.async.pool.NettyChannelTracker - Channel [0xb354eed2] released back to the pool
2023-12-22T10:36:40.182085603 FINE org.neo4j.driver.internal.cluster.RoutingTableHandlerImpl - Fetched cluster composition for database 'system'. ClusterComposition{readers=[localhost:7687], writers=[localhost:7687], routers=[localhost:7687], expirationTimestamp=1703238100176, databaseName=system}
2023-12-22T10:36:40.185015699 FINE org.neo4j.driver.internal.cluster.RoutingTableHandlerImpl - Updated routing table for database 'system'. Ttl 1703238100176, currentTime 1703237800184, routers [localhost:7687], writers [localhost:7687], readers [localhost:7687], database 'system'
2023-12-22T10:36:40.18530819 INFO org.neo4j.driver.internal.InternalDriver - Closing driver instance 1651855867
2023-12-22T10:36:40.186508052 FINE org.neo4j.driver.internal.async.outbound.OutboundMessageHandler - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] C: GOODBYE
2023-12-22T10:36:40.187291369 INFO org.neo4j.driver.internal.async.pool.ConnectionPoolImpl - Closing connection pool towards localhost(127.0.0.1):7687
2023-12-22T10:36:40.189599992 FINE org.neo4j.driver.internal.async.inbound.ChannelErrorHandler - [0xb354eed2][localhost(127.0.0.1):7687][bolt-5] Channel is inactive
2023-12-22T10:36:40.395356347 FINE io.netty.buffer.PoolThreadCache - Freed 6 thread-local buffer(s) from thread: Neo4jDriverIO-2-2
自定义地址解析器
创建 Driver
对象时,您可以指定一个解析器函数来解析驱动程序初始化时连接的地址。请注意,驱动程序在路由表中接收到的地址不会通过自定义解析器进行解析。
您可以通过 .withResolver()
配置方法指定解析器,该方法与 ServerAddress
对象配合使用。
example.com
的 9999
端口被解析为 localhost
的 7687
端口// import java.util.Set;
// import org.neo4j.driver.AuthTokens;
// import org.neo4j.driver.Config;
// import org.neo4j.driver.GraphDatabase;
// import org.neo4j.driver.net.ServerAddress;
var addresses = Set.of(
ServerAddress.of("localhost", 7687) // omit the scheme; provide only host
);
var config = Config.builder()
.withResolver(address -> addresses)
.build();
try (var driver = GraphDatabase.driver("neo4j://example.com:9999", AuthTokens.basic(dbUser, dbPassword), config)) {
driver.verifyConnectivity();
}
OCSP 装订
有两个方法实现此功能:
-
.withVerifyIfPresentRevocationChecks()
— 如果可用,验证证书的装订,但如果未找到装订,则不使验证失败。 -
.withStrictRevocationChecks()
— 验证证书的装订,如果未找到装订,则使验证失败。
这两种方法都作用于 Config.TrustStrategy
对象,因此您必须明确要信任哪些证书,并且不能依赖驱动程序从连接 URI 方案推断。这意味着您必须将这些方法链接到 Config.TrustStrategy.trustSystemCertificates()
。为避免配置冲突,连接 URI 方案也必须设置为 neo4j
(即不是 neo4j+s
或 neo4j+ssc
)。
// import org.neo4j.driver.Config;
Config config = Config.builder()
.withEncryption()
.withTrustStrategy(Config.TrustStrategy
.trustSystemCertificates()
.withVerifyIfPresentRevocationChecks())
.build();
try (var driver = GraphDatabase.driver(dbUri, AuthTokens.basic(dbUser, dbPassword), config)) {
driver.verifyConnectivity();
}
更多连接参数
您可以在API 文档 → driver.GraphDatabase 中找到所有 Driver
配置参数。
词汇表
- LTS
-
长期支持版本是指保证支持多年的版本。Neo4j 4.4 是 LTS 版本,Neo4j 5 也将有一个 LTS 版本。
- Aura
-
Aura 是 Neo4j 的完全托管云服务。它提供免费和付费计划。
- Cypher
-
Cypher 是 Neo4j 的图查询语言,可让您从数据库中检索数据。它类似于 SQL,但用于图。
- APOC
-
Awesome Procedures On Cypher (APOC) 是一个(许多)函数库,这些函数本身无法在 Cypher 中轻松表达。
- Bolt
-
Bolt 是 Neo4j 实例和驱动程序之间交互使用的协议。它默认监听端口 7687。
- ACID
-
原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)(ACID)是保证数据库事务可靠处理的属性。符合 ACID 的 DBMS 可确保数据库中的数据在发生故障时仍保持准确和一致。
- 最终一致性
-
如果数据库能够保证所有集群成员在某个时间点都将存储最新版本的数据,则该数据库是最终一致的。
- 因果一致性
-
如果读写查询以相同的顺序被集群的每个成员看到,则数据库是因果一致的。这比最终一致性更强。
- NULL
-
空标记不是类型,而是值缺失的占位符。欲了解更多信息,请参阅Cypher → 使用
null
。 - 事务
-
事务是工作单元,要么整体提交,要么在失败时回滚。一个例子是银行转账:它涉及多个步骤,但它们必须全部成功或全部回退,以避免钱从一个账户扣除但未添加到另一个账户的情况。
- 背压
-
背压是阻碍数据流动的力。它确保客户端不会被比它能处理的速度更快的数据所淹没。
- 事务函数
-
事务函数是由
executeRead
或executeWrite
调用执行的回调。驱动程序在服务器故障时自动重新执行回调。 - Driver
-
一个
Driver
对象包含与 Neo4j 数据库建立连接所需的详细信息。