¿Puedo exponer una ruta sin autenticación?

¿Existe alguna manera de crear una ruta que omita la autenticación?

Esto se utiliza para integrarse con servicios de terceros.
El requisito es proporcionar al servicio una URL (no se admiten encabezados ni cargas de ningún tipo).
Anteriormente, esto era posible añadiendo “?api_key=…&api_username=”, pero esa opción ya no está disponible.

La instancia de Discourse está alojada por nosotros.

Necesitarías un plugin personalizado que cree una ruta capaz de aceptar un payload y actuar sobre él. Ten en cuenta que, dado que no puedes autenticar al usuario, es posible que necesites una forma de autenticar el payload.

Mi regla es no permitir cuentas anónimas. Por lo tanto, no puedo acceder a las rutas del plugin. Lo que necesito es una forma de crear una ruta para este tipo de escenario.

Por ejemplo,

  # Rails 3.2 por defecto permite que la solicitud pase con una sesión en blanco
  # aquí somos más estrictos y anulamos la sesión / current_user
  # y luego lanzamos una excepción CSRF
  def handle_unverified_request
    # NOTA: La clave API es secreta; tenerla invalida la necesidad de un token CSRF
    unless is_api? || is_user_api?
      super
      clear_current_user
      render plain: "[\"BAD CSRF\"]", status: 403
    end
  end

Una forma de notificar, durante este flujo o durante todo el proceso de autenticación, que un controlador y una acción recibidos mediante parámetros (establecidos automáticamente al llamar a una ruta) pueden omitir todo y ejecutar la ruta.

No tengo pleno conocimiento de cómo funciona todo, pero dado que existe una opción de acceso anónimo, estoy seguro de que hay una manera de hacerlo.

Esto permitiría que las personas cifren la carga útil si es necesario, pero para la actualización de información genérica del sistema, sería muy útil.

Mediante un plugin, puedes agregar tu nueva ruta a DiscoursePluginRegistry.api_parameter_routes para que puedas seguir pasando credenciales de API a través de parámetros de consulta:

También necesitarás la siguiente línea

skip_before_action :redirect_to_login_if_required

en tu controlador personalizado, si este es un sitio que requiere inicio de sesión.

Ok. Sobrescribe ese método y omite la acción. Intentaré y les avisaré si tengo éxito.

# Por defecto, solo permitimos encabezados para enviar credenciales de la API
  # Sin embargo, en algunos escenarios es esencial enviarlas mediante parámetros de URL,
  # por lo que necesitamos agregar algunas excepciones
  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 'Permitido'
      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

Hice esto solo para minimizar los diffs de git en el futuro.

Además, mi controlador:

# frozen_string_literal: true

class MExposedController < ::ApplicationController

  skip_before_action :redirect_to_login_if_required, raise: false

  def endpoint
    render json: { state: "hola mundo" }
  end

end

Así que ahora el endpoint no verifica las credenciales de los parámetros ni de las cabeceras.

¿Cómo puedo hacer que verifique la clave API proporcionada y solo permita el acceso si es válida? (Como solía funcionar)

@riking @blake ?

Creo que añadir requires_login a tu controlador hará el truco. Echa un vistazo a algunos de los otros controladores en app/controllers para ver ejemplos.

Bueno, eso no funcionó :slight_smile:

class MExposedController < ::ApplicationController

  requires_login

  skip_before_action :redirect_to_login_if_required, raise: false

Completado 403 Prohibido

{"errors":["Necesitas iniciar sesión para hacer eso."],"error_type":"not_logged_in"}

Esto está declarado dentro de un plugin.

¿Y pasaste tus credenciales de API a través de los parámetros de consulta? Si es así, es probable que tu ruta no se haya agregado correctamente a la excepción para permitir credenciales de API en los parámetros de consulta. Es posible que necesites depurar la lógica de la excepción y verificar si tu ruta se agregó en algún momento.

Bueno, funciona y elude todo sin requires_login. Publiqué cómo lo hice. Hmm..

Parece que solo puedo hacerlo funcionar sin credenciales. Bueno, al menos he resuelto mi problema inicial.