【问题标题】:How to get the user IP address in Meteor server?如何在 Meteor 服务器中获取用户 IP 地址?
【发布时间】:2013-01-28 09:21:31
【问题描述】:

我想在服务器端获取我的流星应用程序中的用户 IP 地址,以便我可以用一堆东西记录 IP 地址(例如:订阅邮件列表的非注册用户,或只是做任何重要的)。

我知道当涉及反向代理时,服务器“看到”的 IP 地址可能与真实源地址不同。在这种情况下,应解析X-Forwarded-For 标头以获取用户的真实公共IP 地址。请注意,解析 X-Forwarded-For 不应是自动的(有关潜在安全问题的讨论,请参阅 http://www.openinfo.co.uk/apache/index.html)。

外部参考:这个问题出现在meteor-talk mailing list in august 2012(没有提供解决方案)。

【问题讨论】:

标签: meteor


【解决方案1】:

您可以在服务器代码中执行此操作:

Meteor.userIPMap = [];
__meteor_bootstrap__.app.on("request", function(req, res) {
    var uid = Meteor.userId();
    if (!uid) uid = "anonymous";
    if (!_.any(Meteor.userIPMap, function(m) { m.userid === uid; })) {
        Meteor.userIPMap.push({userid: uid, ip: req.connection.remoteAddress });
    }
});

然后,您将拥有一个 Meteor.userIPMap,其中包含用户 ID 到 IP 地址的映射(以容纳上面的 x-forwarded-for 标头 use this function)。

三个注意事项:(1)当您的应用程序中有请求时,它会触发,所以我不确定这会导致什么样的性能损失; (2) __meteor_bootstrap__ 对象很快就会消失,我认为随着即将改进的包系统; (3) anonymous 用户在这里需要更好的处理..您需要一种通过匿名用户的请求对象中的唯一、持久约束将其附加到 IP 的方法。

【讨论】:

  • 看起来是一个非常简单和酷的解决方案:我想我会为此编写一个氛围包。非常感谢,我会尽快测试!
  • 不幸的是,它不起作用(流星 0.5.9):“错误:流星代码必须始终在光纤内运行” - 问题出在 Meteor.userId() 中。 - 真可惜,我真的很喜欢你的想法。
【解决方案2】:

类似于 TimDog 的答案,但适用于较新版本的 Meteor:

var Fiber = Npm.require('fibers');

__meteor_bootstrap__.app
  .use(function(req, res, next) {
    Fiber(function () {
      console.info(req.connection.remoteAddress);
      next();
    }).run();
  });

这需要在您的顶级服务器代码中(而不是在 Meteor.startup 中)

【讨论】:

  • 如何将其链接到 Meteor.user ?
  • 感谢您的贡献。它得到一个 IP 地址,但我总是得到 127.0.0.1 - 我认为这是因为 Meteor 使用 http 代理启动第一个实例,该代理将请求转发到第二个实例。传入的请求总是 127.0.0.1。
  • 对我们来说幸运的是 - http 代理转发传入的 ip,因此我们可以执行以下操作:console.info(req.headers['x-forwarded-for']); - 但是,我仍然无法将其链接到当前用户,因为无法直接调用 Meteor.userId()(错误:Meteor.userId 只能在方法调用中调用。在发布函数中使用 this.userId。)。有什么想法吗?
  • 有没有人想出一个可行的版本?我总是得到 127.0.0.1 作为回应。我正在向客户端中的 ipinfo.io 之类的服务发出 JSONP 请求,这绝对不理想。
【解决方案3】:

你必须连接到服务器会话并获取当前用户的 ip:

Meteor.userIP = function(uid) {
      var k, ret, s, ss, _ref, _ref1, _ref2, _ref3;
      ret = {};
      if (uid != null) {
            _ref = Meteor.default_server.sessions;
            for (k in _ref) {
                  ss = _ref[k];
                  if (ss.userId === uid) {
                        s = ss;
                  }
            }
            if (s) {
                  ret.forwardedFor = ( _ref1 = s.socket) != null ? 
                        ( _ref2 = _ref1.headers) != null ? 
                        _ref2['x-forwarded-for'] : void 0 : void 0;
                  ret.remoteAddress = ( _ref3 = s.socket) != null ? 
                        _ref3.remoteAddress : void 0;
            }
      }
      return ret.forwardedFor ? ret.forwardedFor : ret.remoteAddress;
};

当然,您需要当前用户登录。如果您需要匿名用户,请关注我写的this post

附:我知道这是一个旧线程,但它缺乏完整的答案或代码不再有效。

【讨论】:

  • 非常抱歉,我之前没有考虑或回复您的帖子。您共享的链接现在是 404。你能更新一下吗?如果它也适用于匿名用户,我很乐意确认您的答案是正确的!
【解决方案4】:

这是一种对我有用的方法,它可以从服务器上的任何位置获取客户端的 IP 地址,而无需使用其他软件包。在 Meteor 0.7 中工作,也应该在早期版本中工作。

在客户端,获取套接字 URL(唯一)并将其发送到服务器。您可以在 Web 控制台中查看套接字 URL(在 Chrome 和 Safari 中的网络下)。

socket_url = Meteor.default_connection._stream.socket._transport.url
Meteor.call('clientIP', socket_url)

然后,在服务器上,使用客户端的套接字 URL 在Meteor.server.sessions 中找到它们的 IP。

sr = socket_url.split('/')
socket_path = "/"+sr[sr.length-4]+"/"+sr[sr.length-3]+"/"+sr[sr.length-2]+"/"+sr[sr.length-1]
_.each(_.values(Meteor.server.sessions), (session) ->
    if session.socket.url == socket_path
        user_ip = session.socket.remoteAddress
)

user_ip 现在包含已连接客户端的 IP 地址。

【讨论】:

  • 这行得通,但是当您尝试将 IP 地址用于安全目的时,依靠客户端查找 IP 还不够好。太容易造假了。用户只需打开控制台并调用 Meteor.call('whatever IP')。
  • 好吧,伪造并不是那么容易,因为您要检查Meteor.server.sessions 以获取客户端发送给您的正确 SockJS URL。 (SockJS URL 是唯一的,例如/sockjs/580/uqafmf0o)。如果您没有找到客户端发送给您的 URL,则您知道他们在伪造它,因此您返回错误。不知道你上面的评论是什么意思,但客户端没有在上面的代码中向服务器发送他们的 IP。
【解决方案5】:

1 - 在没有 http 请求的情况下,您应该能够在函数中获取 clientIP:

clientIP = this.connection.clientAddress;
//EX: you declare a submitForm function with Meteor.methods and 
//you call it from the client with Meteor.call().
//In submitForm function you will have access to the client address as above

2 - 使用 http 请求并使用 iron-router 及其 Router.map 函数:

在目标路由的action函数中使用:

clientIp = this.request.connection.remoteAddress;

3 - 使用 Meteor.onConnection 函数:

Meteor.onConnection(function(conn) {
    console.log(conn.clientAddress);
});

【讨论】:

  • 看起来新奇而令人兴奋。你知道这是什么时候添加到 Meteor 中的吗?
  • 不知道第一个是什么时候添加的。不幸的是,我的第二个示例使用的是 express,但可以使用 iron-router 类似地完成,并且在操作函数中您可以使用 this.connection.clientAddress 或 this.request.connection.clientAddress;我会尽快更新我的帖子。
  • 请记住,如果您使用代理,这些将不起作用。在这种情况下,您可以尝试类似this.connection.httpHeaders['x-real-ip'] 或代理添加到数据包中的任何标头。这对我有用 nginx
  • Sarfata:我认为添加了客户信息around Jan 2014。 (向@Andrew-Mao 的answer 致敬)。该值现在内置在核心中 - 请参阅 clientAddress docs.meteor.com/#/full/meteor_onconnection
  • 我在 nginx 代理后面运行。我必须在我的 nginx 配置中将 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 设置为 location / {process.env.HTTP_FORWARDED_COUNT = 2; 作为 Meteor 环境值,而不是像 Meteor 文档中所述的 1。我也很幸运Meteor.onConnection(function(conn) { var forwardedFor = conn.httpHeaders['x-forwarded-for'].split(","); console.log(forwardedFor[0]); });
【解决方案6】:

这个答案https://stackoverflow.com/a/22657421/2845061 已经很好地展示了如何获取客户端 IP 地址。

我只想指出,如果您的应用在代理服务器之后提供服务(通常会发生),您需要将 HTTP_FORWARDED_COUNT 环境变量设置为数字您正在使用的代理数量。

参考:https://docs.meteor.com/api/connections.html#Meteor-onConnection

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-01
    • 2010-11-23
    • 2011-03-27
    • 2011-02-07
    相关资源
    最近更新 更多