Nous allons développer une petite application API dans Sinatra. Quelles sont les options d'authentification disponibles pour sécuriser les appels d'API?
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
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.)
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'