【问题标题】:Handling websocket connection on invalid token in Elixir/Phoenix在 Elixir/Phoenix 中处理无效令牌上的 websocket 连接
【发布时间】:2019-07-07 15:16:39
【问题描述】:

我们使用 Guardian 生成令牌,然后在连接到 Phoenix Channels 的套接字时用于身份验证。

最近我们发现有些用户从不离开某些页面,并且在一个月左右之后,令牌变得无效,这使得凤凰频道的连接尝试无效。

您如何在客户端处理此类情况?有没有特定的错误可以从 Phoenix 返回让前端知道是什么原因? user_socket.ex 中的 connect 函数如下所示:

def connect(%{"guardian_token" => token}, socket) do
  case Guardian.Phoenix.Socket.authenticate(socket, MyApp.Guardian, token) do
    {:ok, authed_socket} ->
      {:ok, authed_socket}

    {:error, _} ->
      :error
  end
end

有没有办法使用 Phoenix 频道的 Phoenix JS 库捕获此错误?我们的目标是 1)在令牌过期时阻止它重试,2)可能注销用户或显示用户离线的消息。我们检查了Phoenix JS' documentation,但找不到合适的。

【问题讨论】:

  • 这是一个非常古老的问题,但客户端似乎仍然没有办法知道“错误”是否是因为连接断开(可能是在重新部署应用程序时)或来自身份验证错误,如无效令牌。

标签: elixir phoenix-framework phoenix-channels


【解决方案1】:

您可以尝试在每次连接时或在您认为合适的时候刷新令牌

可能是这样的

# Refresh a token and set it on connect
def connect(%{"guardian_token" => token}, socket) do

  case MyApp.Guardian.refresh(token) do

    {:ok, _old_stuff, {new_token, new_claims}} -> 
      case Guardian.Phoenix.Socket.authenticate(socket, MyApp.Guardian, new_token, new_claims) do
        {:ok, authed_socket} ->
          {:ok, authed_socket}
        {:error, _} ->
          :socket_auth_failed
      end

    _ ->
      {:token_refresh_failed, "could not refresh token"}
  end
end

【讨论】:

  • 感谢您的建议。我们确实希望令牌过期(并确保用户再次重新验证)。我将修改问题以使其更清楚目标是什么。谢谢!
【解决方案2】:

这可以在客户端处理。

下面是一些演示自动断开流程的伪代码:

// Assuming you are adding the token (JWT) to the socket URL's query parameters
const socket = new Socket(url, { params: { jwt }});
socket.connect();

// Listen to socket errors
socket.onError(error => {
  if (!isValidJwt(jwt)) {
    console.log("JWT is no longer valid. Disconnecting.");
    socket.disconnect();
  }
})

function isValidJwt(jwt) {
  // Provide your own validation logic here
  // For JWTs, you can parse the JWT, read the expiration time,
  // and compare it with the current time.
}

此外,您可以通过对服务器端代码进行临时修改来进行本地测试。

在您生成身份验证令牌的地方,给令牌一个小的生存时间 (TTL):

// Temporary change, for testing
conn = MyApp.Guardian.Plug.sign_in(conn, user, %{}, ttl: {10, :second})

这会使 JWT 在 10 秒后过期。

通过修改后的服务器端更改,让客户端登录并连接到套接字。杀死 Phoenix 服务器以触发 socket 对象的自动重新连接机制。在尝试重新连接时出现socket 错误,您的回调函数会注意到令牌不再有效,并且会断开套接字。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-12
    • 2013-05-02
    相关资源
    最近更新 更多