【问题标题】:how to get remote_ip from socket in phoenix-framework?如何从 phoenix-framework 中的套接字获取 remote_ip?
【发布时间】:2016-01-21 10:43:58
【问题描述】:

如何从phoenixframework中的socket获取remote_ip?我可以从 View 中的 conn 获取它,但不能在 Channel 中获取。

非常感谢您的帮助!

【问题讨论】:

    标签: sockets ip elixir phoenix-framework


    【解决方案1】:

    现在的答案是:你不能。您无法访问通道中的连接,因为通道与传输无关。在 Phoenix 中打开一个问题,详细说明您的用户案例,以便 Phoenix 团队可以采取行动。

    【讨论】:

      【解决方案2】:

      此处提供的答案副本:https://elixirforum.com/t/phoenix-socket-channels-security-ip-identification/1463/3(所有功劳归于https://elixirforum.com/u/arjan

      凤凰 1.4 更新:

      从 Phoenix 1.4 开始,您可以从底层传输中获取连接信息。您获得的信息类型取决于传输,但使用 WebSocket 传输可以检索对等信息(IP 地址)和 x-headers 列表(用于 x-forwarded-for 解析)。

      在您的 endpoint.ex 中像这样配置您的套接字:

      socket("/socket", MyApp.Web.UserSocket,
        websocket: [connect_info: [:peer_data, :x_headers]],
        longpoll: [connect_info: [:peer_data, :x_headers]]
      )
      

      然后你的 UserSocket 模块必须像这样公开一个 connect/3 函数:

      def connect(_params, socket, connect_info) do
        {:ok, socket}
      end
      

      在连接时,connect_info 参数现在包含来自传输的信息:

      info: %{
        peer_data: %{address: {127, 0, 0, 1}, port: 52372, ssl_cert: nil},
        x_headers: []
      }
      

      更新

      如果您的 Phoenix 应用程序没有直接处理流量,而是从反向代理(如 nginx)接收流量,那么 peer_data 将拥有 nginx IP 地址,而不是客户端的 IP 地址。 要解决此问题,您可以告诉 nginx(或您使用的任何代理)在标头中传递原始 IP,然后稍后再阅读。

      所以你的凤凰位置应该是这样的:

      location /phoenix/ {
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host $http_host;
          proxy_redirect off;
          proxy_pass http://phoenix/;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "Upgrade";
      }
      

      你的套接字代码应该有这个:

      defp get_ip_address(%{x_headers: headers_list}) do
        header = Enum.find(headers_list, fn {key, _val} -> key == "x-real-ip" end)
      
        case header do
          nil ->
            nil
      
          {_key, value} ->
            value
      
          _ ->
            nil
        end
      end
      
      defp get_ip_address(_) do
        nil
      end
      

      并将连接更改为类似的东西

      def connect(params, socket, connect_info) do
        socket = assign(socket, :ip_address, get_ip_address(connect_info))
        {:ok, socket}      
      end
      

      【讨论】:

      • 我正在使用此代码,似乎 peer_data 中的地址不是公共远程 IP。我只获得私人 ip(如 10.x.x.x)。有没有办法获取远程公网IP?
      • 当然,您只需要告诉您的反向代理服务器将该信息传递给 Phoenix。请参阅serverfault.com/questions/955533/… 或谷歌搜索。 UPDATE 看来我不能在 cmets 中添加格式化代码,所以我会更新答案
      • 谢谢。我意识到这是由于 Heroku 上的代理,所以我使用 x_headers 中的 x-forwarded-for 作为解决方案。我之前尝试过使用 peer_data.address。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-23
      • 1970-01-01
      • 2011-05-20
      • 2021-01-06
      • 2013-04-27
      相关资源
      最近更新 更多