web-dev-qa-db-fra.com

Rails: le meilleur moyen d'implémenter l'authentification?

J'écris une application Rails 4) qui exposera une API pour une application mobile qui n'a pas encore été développée. Les utilisateurs s'authentifieront à l'aide d'un e-mail et d'un mot de passe provenant de l'application mobile.

Bien que j'ai trouvé pas mal d'informations sur le sujet. Il est difficile de discerner ce qui est périmé ou non optimal. J'ai lu sur HTTP Basic Auth, qui ne semble pas trop sécurisé, et sur HTTP Token, mais je ne suis pas sûr de savoir comment associer cela à une authentification habituelle par e-mail et par mot de passe (j'utilise Devise de le chemin).

J'aimerais juste savoir quelle est la meilleure pratique actuelle sur la façon de mettre en œuvre cela, alors je vais être sûr d'aller dans le bon sens.

75
Roma149

Le point important, du point de vue de la sécurité, consiste à échanger une fois le courrier électronique et le mot de passe de l'utilisateur contre un jeton, puis à utiliser ce jeton pour les demandes suivantes. Ceci est dû au fait:

  1. Vous ne souhaitez pas que l'application cliente conserve le mot de passe de l'utilisateur, car un bogue ou une attaque pourrait en provoquer la fuite; et
  2. Un jeton émis par le serveur vous permet (ainsi qu'à vos utilisateurs) d'exprimer un jeton si nécessaire, par exemple. pour verrouiller un périphérique volé ou bloquer un client API défectueux.

Il existe de nombreuses façons d’y parvenir avec différents niveaux de complexité.

Voici un didacticiel très récent doté d'une procédure détaillée pour la création d'une API dans Rails avec authentification par jeton (sans utiliser Devise, mais permettant de comprendre les concepts)): https://labs.kollegorna.se/blog/2015/04/build-an-api-now/

48
Matt Brictson

Une autre option consiste à inclure le module ci-dessous dans votre modèle de modèle et à ajouter l'auth_token à votre table.

app/models/concerne/token_authenticable.rb

module TokenAuthenticatable
  extend ActiveSupport::Concern

  included do
    before_save :ensure_auth_token
  end

  module ClassMethods
    def find_by_token(token)
      find_by(auth_token: token)
    end
  end

  def ensure_auth_token
    self.auth_token = generate_auth_token if auth_token.blank?
  end

  private

  def generate_auth_token
    loop do
      token = Devise.friendly_token
      break token unless self.class.exists?(auth_token: token)
    end
  end
end

app/controllers/api/v1/login_controller.rb

...
 def login_user(params)
    if params[:authentication]
      @user = User.find_by(auth_token: params[:authentication])
      if @user.nil?
        render json: err('login user by token failed', ERR_USER_NOT_FOUND), status: :not_found
        event('login_user_by_auth_failed', 'token', params[:authentication])
        return
      else
        render status: :ok, json: @user
        return
      end
    else
      user = user.find_by(email: params[:email])
      if user.nil?
        event('login_user_failed_not_found', 'user_email', params[:email])
        render json: err("login user not found #{params[:email]}", ERR_USER_NOT_FOUND), status: :not_found
        return
      end
      if user.access_locked?
        event('login_user_blocked', 'user_id', user.id)
        render json: err("login user account is locked : #{user.id}", ERR_USER_LOCKED), status: :unauthorized
        return
      end
      unless user.try(:valid_password?, params[:password])
        event("login_user_password_does_not_match #{user.id}", 'user_id',  user.id)
        render json: err('login user password does not match', ERR_PASSWORD_NOT_MATCH), status: :unauthorized
        return
      end
      event('login_user_succeeded', 'user_id', user.id)
      @user= user
      if @user.save
        response.headers['authentication'] = @user.auth_token
        render status: :ok, json: @user
        return
      else
        render json: @user.errors, status: :unprocessable_entity
        return
      end
    end
  end
...

Edit: correction d'une faute de frappe

5
Antarr Byrd

@ Roma149, c'est plus une préférence personnelle, mais la plupart des débutants utilisent Devise, car c'est l'OMI la plus simple. OAuth2 est également une bonne option. Comme note plus importante, vous pouvez toujours aller à La Ruby Toolbox

Il y a beaucoup de bonnes informations sur les gemmes là-bas et ils vous disent même l'âge et la popularité de la gemme. Cela vous permettra également de faire la distinction entre les joyaux de la communauté et ceux qui sont obsolètes.

Rappelez-vous dans Ruby et Ruby sur Rails, ce n'est pas toujours ce qui est le mieux au niveau des pierres précieuses, mais celui qui convient le mieux à votre projet!)!

4
The Gugaru

Tiddle gem fournit une stratégie de conception pour l'authentification de jeton dans l'API uniquement Ruby sur Rails = applications. Sa principale caractéristique est le support de plusieurs jetons par utilisateur .

https://github.com/adamniedzielski/tiddle

3
Zakaria