web-dev-qa-db-fra.com

Sinatra - API - Authentification

Nous allons développer une petite application API dans Sinatra. Quelles sont les options d'authentification disponibles pour sécuriser les appels d'API?

57
Saim

Sinatra n'a pas de support d'authentification intégré. Certains joyaux sont disponibles, mais la plupart sont conçus pour l’authentification des utilisateurs (par exemple, pour un site Web). Pour une API, ils semblent excessifs. C’est assez facile de créer le vôtre. Il suffit de vérifier les paramètres de demande dans chacune de vos routes pour voir s’ils contiennent une clé API valide et, dans le cas contraire, renvoyer une erreur 401.

helpers do
  def valid_key? (key)
    false
  end
end

get "/" do
  error 401 unless valid_key?(params[:key])

  "Hello, world."
end

#  $ irb -r open-uri
#  >> open("http://yourapp.com/api/?key=123")
#  OpenURI::HTTPError: 401 Unauthorized

Après l'appel à error, rien ne se passera si votre méthode valid_key? renvoie false - error appelle halt en interne, ce qui empêche la poursuite de la demande.

Bien sûr, il n’est pas idéal de répéter le contrôle au début de chaque itinéraire. Au lieu de cela, vous pouvez créer une petite extension qui ajoute des conditions à vos itinéraires:

class App < Sinatra::Base
  register do
    def check (name)
      condition do
        error 401 unless send(name) == true
      end
    end
  end

  helpers do
    def valid_key?
      params[:key].to_i % 2 > 0
    end
  end

  get "/", :check => :valid_key? do
    [1, 2, 3].to_json
  end
end

Si vous souhaitez simplement une authentification sur toutes vos routes, utilisez un gestionnaire before:

before do
  error 401 unless params[:key] =~ /^xyz/
end

get "/" do
  {"e" => mc**2}.to_json
end
89
Todd Yandell

http://www.secondforge.com/blog/2014/11/05/simple-api-authentication-in-sinatra/ a une réponse légèrement plus détaillée qui utilise des jetons d'utilisateur. 

C'est une étape plus compliquée qu'une clé d'API, mais elle est nécessaire si votre API a besoin d'une authentification pour permettre à un utilisateur de se connecter, par exemple en modifiant un nom/une adresse électronique/un mot de passe ou en accédant à des informations par utilisateur. (c'est-à-dire des actions "privées" de l'API). Vous pouvez également révoquer/expirer les jetons utilisateur pour permettre aux utilisateurs de se déconnecter, etc. 

class App < Sinatra::Base

  before do
    begin
      if request.body.read(1)
        request.body.rewind
        @request_payload = JSON.parse request.body.read, { symbolize_names: true }
      end
    rescue JSON::ParserError => e
      request.body.rewind
      puts "The body #{request.body.read} was not JSON"
    end
  end

  post '/login' do
    params = @request_payload[:user]

    user = User.find(email: params[:email])
    if user.password == params[:password] #compare the hash to the string; magic
      #log the user in
    else
      #tell the user they aren't logged in
    end
  end
end

(Il est intéressant de noter qu'il est plus courant de lire les informations d'identification à partir d'un en-tête HTTP au lieu du corps JSON, mais l'auteur le mentionne.)

2
chug2k

Mettre à jour

De nos jours, l'authentification par jeton est de plus en plus populaire. Je recommanderais d'utiliser l'implémentation Ruby du standard JWT par Ruby-jwt pour une authentification et une autorisation simples.

gem 'jwt'
0
Marcelo Fonseca