¿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:
# 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
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.
¿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.