是否可以暴露一个没有身份验证的路由?

有没有办法创建一条绕过身份验证的路由?

这用于与第三方服务集成。
要求是向服务提供一个 URL(不支持任何类型的请求头或负载)。
以前可以通过附加“?api_key=…&api_username=”来实现,但现在该方式已不可用。

Discourse 实例由我们托管。

3 个赞

您需要一个自定义插件,该插件可以创建一条能够接收负载并对其进行处理的路线。请注意,由于您无法对用户进行身份验证,因此可能需要一种方法来验证负载。

3 个赞

我的规则是不允许匿名账户。因此,我无法访问插件路由。我需要一种方法,为这种场景创建路由。

例如:

  # 默认情况下,Rails 3.2 会允许空会话的请求通过
  # 但我们在这里更加严格,将 session 和 current_user 设为 null
  # 然后抛出 CSRF 异常
  def handle_unverified_request
    # 注意:API 密钥是保密的,使用它后就不再需要 CSRF 令牌
    unless is_api? || is_user_api?
      super
      clear_current_user
      render plain: "[\"BAD CSRF\"]", status: 403
    end
  end

我需要一种方式,在此流程或整个认证流程中通知系统:某个控制器和通过参数传递的动作(在调用路由时自动设置)可以绕过所有检查并直接执行该路由。

我对整个机制并非完全了解,但既然存在匿名访问选项,我相信一定有办法实现这一点。

这样,如果需要,用户可以对负载进行加密;而对于系统通用信息的更新,这将非常有用。

1 个赞

通过插件,您可以将新路由添加到 DiscoursePluginRegistry.api_parameter_routes 中,以便继续通过查询参数传递 API 凭据:

4 个赞

如果这是一个需要登录的网站,您还需要在自定义控制器中添加以下代码段:

skip_before_action :redirect_to_login_if_required
2 个赞

好的。那么覆盖该方法并跳过操作。我会尝试一下,如果成功再通知大家。

1 个赞
# 默认情况下,我们仅允许通过请求头发送 API 凭据
  # 但在某些场景下,必须通过 URL 参数发送这些凭据
  # 因此我们需要添加一些例外情况
  def api_parameter_allowed?
    request_method = @env["REQUEST_METHOD"]&.downcase&.to_sym
    request_format = @env['action_dispatch.request.formats']&.first&.symbol

    path_params = @env['action_dispatch.request.path_parameters']
    request_route = "#{path_params[:controller]}##{path_params[:action]}" if path_params

    if 'm_exposed#endpoint' == request_route && request_method == 'get'
      puts '允许'
      return true
    end

    PARAMETER_API_PATTERNS.any? do |p|
      (p[:method] == "*" || Array(p[:method]).include?(request_method)) &&
      (p[:format] == "*" || Array(p[:format]).include?(request_format)) &&
      (p[:route] == "*" || Array(p[:route]).include?(request_route))
    end
  end

我这样做的目的是为了最小化未来的 Git 差异。

此外,我的控制器如下:

# frozen_string_literal: true

class MExposedController < ::ApplicationController

  skip_before_action :redirect_to_login_if_required, raise: false

  def endpoint
    render json: { state: "hello world" }
  end

end

所以现在该端点不再检查参数或头部凭证。

我该如何让它检查提供的 API 密钥,并仅在密钥有效时才允许访问?(就像以前那样)

@riking @blake

我相信在您的控制器中添加 requires_login 就能解决问题。您可以查看 app/controllers 中的其他控制器以获取示例。

2 个赞

好吧,这不起作用 :slight_smile:

class MExposedController < ::ApplicationController

  requires_login

  skip_before_action :redirect_to_login_if_required, raise: false

已完成 403 禁止访问

{"errors":["您需要登录后才能执行此操作。"],"error_type":"not_logged_in"}

这是在插件内部声明的。

你是通过查询参数传递 API 凭据的吗?如果是的话,这意味着你的路由可能没有正确添加到允许在查询参数中包含 API 凭据的绕过规则中。你可能需要调试绕过逻辑,检查你的路由是否已被添加。

好吧,它确实有效,并且无需登录即可绕过所有限制。我已经贴出了具体方法。嗯……

看来我只能在不使用凭据的情况下让它工作。好吧,至少我解决了最初的问题。