Могу ли я открыть маршрут без аутентификации?

Есть ли способ создать маршрут, который обходит аутентификацию?

Это используется для интеграции со сторонними сервисами.
Требование — предоставить сервису URL (заголовки или полезные данные любого типа не поддерживаются).
Раньше это было возможно, добавляя “?api_key=…&api_username=”, но теперь этот вариант удалён.

Экземпляр Discourse размещён нами.

Вам потребуется специальный плагин, который создаст маршрут, способный принимать полезную нагрузку и обрабатывать её. Обратите внимание: поскольку вы не можете аутентифицировать пользователя, вам, возможно, понадобится способ аутентификации самой полезной нагрузки.

Мое правило — никаких анонимных аккаунтов. Поэтому я не могу получить доступ к маршрутам плагинов. Мне нужен способ создать маршрут для такого сценария.

Например,

  # В Rails 3.2 по умолчанию запрос проходит с пустой сессией
  # Мы же здесь более педантичны: обнуляем сессию / current_user
  # и затем выбрасываем исключение 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

Мне нужен способ уведомить систему в ходе этого процесса или всего процесса аутентификации, что контроллер и действие, полученные через параметры (устанавливаются автоматически при вызове маршрута), могут обойти все проверки и выполнить маршрут.

Я не до конца понимаю, как всё работает, но поскольку есть опция анонимного доступа, я уверен, что способ это сделать существует.

Это позволило бы людям при необходимости шифровать полезную нагрузку, а для обновления системы общей информацией было бы очень полезно.

С помощью плагина вы можете добавить свой новый маршрут в DiscoursePluginRegistry.api_parameter_routes, чтобы продолжать передавать учетные данные API через параметры запроса:

Вам также понадобится строка

skip_before_action :redirect_to_login_if_required

в вашем пользовательском контроллере, если это сайт с обязательным входом.

Хорошо. Переопределите этот метод и пропустите действие. Я попробую и сообщу вам, если у меня получится.

# По умолчанию мы разрешаем отправку учетных данных 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 'Allowed'
      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.

Ну, это не сработало :slight_smile:

class MExposedController < ::ApplicationController

  requires_login

  skip_before_action :redirect_to_login_if_required, raise: false

Завершено с ошибкой 403 Forbidden

{"errors":["Для этого необходимо войти в систему."],"error_type":"not_logged_in"}

Это объявлено внутри плагина.

А вы передали свои учётные данные API через параметры запроса? Если да, то, скорее всего, ваш маршрут не был правильно добавлен в список исключений для разрешения учётных данных API в параметрах запроса. Возможно, вам потребуется отладить логику исключений и проверить, был ли ваш маршрут вообще добавлен.

Ну, это работает и обходит всё без requires_login. Я опубликовал, как это сделал. Хм..

Кажется, я могу заставить это работать только без учётных данных. Ну, по крайней мере, я решил свою первоначальную проблему.