Posso esporre una route senza autenticazione?

C’è qualche modo per creare una rotta che bypassi l’autenticazione?

Questo viene utilizzato per l’integrazione con servizi di terze parti.
Il requisito consiste nel fornire al servizio un URL (non sono supportati né header né payload di alcun tipo).
In precedenza era possibile aggiungendo “?api_key=…&api_username=” ma tale opzione non è più disponibile.

L’istanza di Discourse è ospitata da noi.

Avresti bisogno di un plugin personalizzato che crei una rotta in grado di accettare un payload e agire di conseguenza. Tieni presente che, poiché non sei in grado di autenticare l’utente, potresti aver bisogno di un modo per autenticare il payload.

La mia regola è: nessun account anonimo. Quindi non posso accedere alle rotte del plugin. Ciò di cui avrei bisogno è un modo per creare una rotta per questo tipo di scenario.

Ad esempio,

  # Rails 3.2 predefinito lascia passare la richiesta con una sessione vuota
  # qui siamo più pedanti e annulliamo la sessione / current_user
  # e poi solleviamo un'eccezione CSRF
  def handle_unverified_request
    # NOTA: la chiave API è segreta; averla invalida la necessità di un token CSRF
    unless is_api? || is_user_api?
      super
      clear_current_user
      render plain: "[\"BAD CSRF\"]", status: 403
    end
  end

Un modo per notificare, durante questo flusso o l’intero flusso di autenticazione, che un controller e un’azione ricevuti tramite parametri (impostati automaticamente quando si chiama una rotta) possono bypassare tutto ed eseguire la rotta.

Non sono pienamente consapevole di come funzioni tutto, ma dato che esiste un’opzione di accesso anonimo, sono sicuro che ci sia un modo per farlo.

Ciò permetterebbe alle persone di crittografare il payload se necessario, ma per l’aggiornamento del sistema con informazioni generiche sarebbe utile.

Tramite un plugin, puoi aggiungere la tua nuova rotta a DiscoursePluginRegistry.api_parameter_routes in modo da poter continuare a passare le credenziali API tramite parametri di query:

Avrai anche bisogno di questa riga:

skip_before_action :redirect_to_login_if_required

nel tuo Controller personalizzato, se si tratta di un sito che richiede l’accesso.

Ok. Quindi sovrascrivi quel metodo e salta l’azione. Proverò e vi farò sapere se ci riesco.

# Di default permettiamo solo le intestazioni per l'invio delle credenziali API
  # Tuttavia, in alcuni scenari è essenziale inviarle tramite parametri URL
  # quindi dobbiamo aggiungere alcune eccezioni
  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 'Consentito'
      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

Ho fatto questo solo per minimizzare le differenze git future.

Inoltre, il mio controller:

# 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

Quindi ora l’endpoint non verifica le credenziali nei parametri o negli header.

Come posso fare in modo che verifichi la chiave API fornita e consenta l’accesso solo se è valida? (Come funzionava prima)

@riking @blake?

Credo che aggiungere requires_login al tuo controller farà al caso tuo. Dai un’occhiata ad alcuni degli altri controller in app/controllers per degli esempi.

Beh, non ha funzionato :slight_smile:

class MExposedController < ::ApplicationController

  requires_login

  skip_before_action :redirect_to_login_if_required, raise: false

Completato 403 Forbidden

{"errors":["È necessario essere collegati per farlo."],"error_type":"not_logged_in"}

Questo è dichiarato all’interno di un plugin.

E hai passato le tue credenziali API tramite parametri di query? Se sì, significa che la tua rotta probabilmente non è stata aggiunta correttamente al bypass per consentire le credenziali API nei parametri di query. Potresti dover eseguire il debug della logica di bypass e verificare se la tua rotta è mai stata aggiunta.

Beh, funziona e aggira tutto senza requires_login. Ho pubblicato come l’ho fatto. Hmm..

Sembra che io possa farlo funzionare solo senza credenziali. Beh, almeno ho risolto il mio problema iniziale.