如何在 SpringBoot 中获取 Rsocket 连接的远程 IP 地址
How do I get the remote IP address for an Rsocket connection in SpringBoot
我正在尝试获取连接到 RSocket+SpringBoot 网络服务器的浏览器的远程 IP。连接是基于 WebSocket 的 RSocket。
Web 服务器是 Java-8,SpringBoot-2,使用 RSocket over WebSocket 并将 RequestStreams 发送到浏览器。我正在利用 SpringBoot autoconfig 进行 RSocket 设置,因此服务器端的代码非常少 - 见下文。
@Headers and MessageHeader
在下面的代码中只是为了看看他们是否有任何可以导致远程 IP 的东西,没有其他原因。
我在网上搜寻答案 - 很多是关于 http 的,一些是关于 websockets 的,zero 是关于 RSocket 的。
这 - https://github.com/rsocket/rsocket-java/issues/735 - 看起来很有希望,但无法获得 DuplexConnection 的句柄,所以那里没有雪茄。
有什么想法吗?谢谢!
application.yml:
spring.rsocket.server:
mapping-path: /rsocket-test
transport: websocket
server.port: 8080
TestController.java
/**
* TODO: get the remote IP address and log.
* Options:
* 1. @see <a href="https://github.com/rsocket/rsocket-java/issues/735">Ability to intercept requests and access channel information such as remote address</a>.
* 2. Inject IP in header by nginx. See if it shows up in the @Headers param here.
* 3. Browser gets its public IP and adds it to the request object. Doable, but lame
* 4. (Unlikely) Find a way to access thru this chain of private members: headers.req.rsocket().source.connection.source.connection.connection.channel.remoteAddress
*/
@MessageMapping("subscribe-topic")
public Flux<StreamingEvent> subscribeToEventStream(
@Headers Map<String,Object> hdrs,
MessageHeaders mh,
testRequest request) {
return testService.subscribeTopic(request.getRequestId(), request.getTopic());
}
客户端的 IP 地址在 DuplexConnection
class 中可用。您可以像这样向 RSocketServer
添加拦截器:
@Bean
public RSocketServerCustomizer ipCustomizer() {
return rSocketServer -> rSocketServer.interceptors(registry -> registry.forConnection(new ConnectionInterceptor()));
}
其中 ConnectionInterceptor
是:
static class ConnectionInterceptor implements DuplexConnectionInterceptor {
@Override
public DuplexConnection apply(Type type, DuplexConnection duplexConnection) {
SocketAddress socketAddress = duplexConnection.remoteAddress();
if (socketAddress instanceof InetSocketAddress) {
InetSocketAddress iso = (InetSocketAddress) socketAddress;
// Here is the ip: iso.getHostString()
}
return duplexConnection;
}
}
在我的方案中,我想将远程主机和原始 HTTP 请求 headers 传递给我的 @MessageMapping
处理程序。我想出的最好方法是创建我自己的 NettyRouteProvider
并使用所需数据丰富订阅上下文:
@Component
public class MyRouteProvider implements NettyRouteProvider {
private final String mappingPath;
private final SocketAcceptor socketAcceptor;
private final List<RSocketServerCustomizer> customizers;
@Autowired
MyRouteProvider(RSocketProperties properties, RSocketMessageHandler messageHandler,
ObjectProvider<RSocketServerCustomizer> customizers) {
this.mappingPath = properties.getServer().getMappingPath();
this.socketAcceptor = messageHandler.responder();
this.customizers = customizers.orderedStream().collect(Collectors.toList());
}
@Override
public HttpServerRoutes apply(HttpServerRoutes httpServerRoutes) {
RSocketServer server = RSocketServer.create(this.socketAcceptor);
this.customizers.forEach((customizer) -> customizer.customize(server));
ServerTransport.ConnectionAcceptor connectionAcceptor = server.asConnectionAcceptor();
return httpServerRoutes.ws(this.mappingPath, (in, out) ->
connectionAcceptor.apply(new WebsocketDuplexConnection((Connection) in)).then(out.neverComplete())
.contextWrite(context -> {
String ip = in.headers().get("x-forwarded-for");
SocketAddress remoteAddress = ((Connection) in).channel().remoteAddress();
if(in.headers().contains("x-forwarded-for")){
return context
.put("remoteHost",remoteAddress)
.put(HttpHeaders.class, in.headers())
.put("client-ip", ip);
}
return context
.put("remoteHost",remoteAddress)
.put(HttpHeaders.class, in.headers());
}));
}
}
在此之后,您将能够在任何 @MessageMapping 方法中从上下文中获取数据,例如:
@MessageMapping("remote-host")
fun remoteHost(): Mono<SocketAddress> {
return Mono.deferContextual { context ->
Mono.just(context.get<SocketAddress>("remoteHost"))
}
}
我正在尝试获取连接到 RSocket+SpringBoot 网络服务器的浏览器的远程 IP。连接是基于 WebSocket 的 RSocket。
Web 服务器是 Java-8,SpringBoot-2,使用 RSocket over WebSocket 并将 RequestStreams 发送到浏览器。我正在利用 SpringBoot autoconfig 进行 RSocket 设置,因此服务器端的代码非常少 - 见下文。
@Headers and MessageHeader
在下面的代码中只是为了看看他们是否有任何可以导致远程 IP 的东西,没有其他原因。
我在网上搜寻答案 - 很多是关于 http 的,一些是关于 websockets 的,zero 是关于 RSocket 的。 这 - https://github.com/rsocket/rsocket-java/issues/735 - 看起来很有希望,但无法获得 DuplexConnection 的句柄,所以那里没有雪茄。
有什么想法吗?谢谢!
application.yml:
spring.rsocket.server:
mapping-path: /rsocket-test
transport: websocket
server.port: 8080
TestController.java
/**
* TODO: get the remote IP address and log.
* Options:
* 1. @see <a href="https://github.com/rsocket/rsocket-java/issues/735">Ability to intercept requests and access channel information such as remote address</a>.
* 2. Inject IP in header by nginx. See if it shows up in the @Headers param here.
* 3. Browser gets its public IP and adds it to the request object. Doable, but lame
* 4. (Unlikely) Find a way to access thru this chain of private members: headers.req.rsocket().source.connection.source.connection.connection.channel.remoteAddress
*/
@MessageMapping("subscribe-topic")
public Flux<StreamingEvent> subscribeToEventStream(
@Headers Map<String,Object> hdrs,
MessageHeaders mh,
testRequest request) {
return testService.subscribeTopic(request.getRequestId(), request.getTopic());
}
客户端的 IP 地址在 DuplexConnection
class 中可用。您可以像这样向 RSocketServer
添加拦截器:
@Bean
public RSocketServerCustomizer ipCustomizer() {
return rSocketServer -> rSocketServer.interceptors(registry -> registry.forConnection(new ConnectionInterceptor()));
}
其中 ConnectionInterceptor
是:
static class ConnectionInterceptor implements DuplexConnectionInterceptor {
@Override
public DuplexConnection apply(Type type, DuplexConnection duplexConnection) {
SocketAddress socketAddress = duplexConnection.remoteAddress();
if (socketAddress instanceof InetSocketAddress) {
InetSocketAddress iso = (InetSocketAddress) socketAddress;
// Here is the ip: iso.getHostString()
}
return duplexConnection;
}
}
在我的方案中,我想将远程主机和原始 HTTP 请求 headers 传递给我的 @MessageMapping
处理程序。我想出的最好方法是创建我自己的 NettyRouteProvider
并使用所需数据丰富订阅上下文:
@Component
public class MyRouteProvider implements NettyRouteProvider {
private final String mappingPath;
private final SocketAcceptor socketAcceptor;
private final List<RSocketServerCustomizer> customizers;
@Autowired
MyRouteProvider(RSocketProperties properties, RSocketMessageHandler messageHandler,
ObjectProvider<RSocketServerCustomizer> customizers) {
this.mappingPath = properties.getServer().getMappingPath();
this.socketAcceptor = messageHandler.responder();
this.customizers = customizers.orderedStream().collect(Collectors.toList());
}
@Override
public HttpServerRoutes apply(HttpServerRoutes httpServerRoutes) {
RSocketServer server = RSocketServer.create(this.socketAcceptor);
this.customizers.forEach((customizer) -> customizer.customize(server));
ServerTransport.ConnectionAcceptor connectionAcceptor = server.asConnectionAcceptor();
return httpServerRoutes.ws(this.mappingPath, (in, out) ->
connectionAcceptor.apply(new WebsocketDuplexConnection((Connection) in)).then(out.neverComplete())
.contextWrite(context -> {
String ip = in.headers().get("x-forwarded-for");
SocketAddress remoteAddress = ((Connection) in).channel().remoteAddress();
if(in.headers().contains("x-forwarded-for")){
return context
.put("remoteHost",remoteAddress)
.put(HttpHeaders.class, in.headers())
.put("client-ip", ip);
}
return context
.put("remoteHost",remoteAddress)
.put(HttpHeaders.class, in.headers());
}));
}
}
在此之后,您将能够在任何 @MessageMapping 方法中从上下文中获取数据,例如:
@MessageMapping("remote-host")
fun remoteHost(): Mono<SocketAddress> {
return Mono.deferContextual { context ->
Mono.just(context.get<SocketAddress>("remoteHost"))
}
}