Mon application Rails utilise Concevoir pour l'authentification. Il a une sœur de l'application iOS, et les utilisateurs peuvent se connecter à l'application iOS en utilisant les mêmes informations d'identification qu'ils utilisent pour l'application web. J'ai donc besoin d'une sorte d'API pour l'authentification.
Beaucoup de questions similaires sur ici point de ce tutoriel, mais il semble être out-of-date, comme l' token_authenticatable
module a depuis été retiré de Concevoir, et certaines des lignes de générer des erreurs. (Je suis l'aide de Concevoir 3.2.2.) J'ai tenté de rouler mes propres basé sur le tutoriel (et ce seul), mais je ne suis pas 100% confiance en elle - je me sens comme il y a peut être quelque chose que j'ai mal compris ou manqués.
Tout d'abord, en suivant les conseils de ce résumé, j'ai ajouté un authentication_token
d'attribut de texte pour ma users
tableau, et le suivant à l' user.rb
:
before_save :ensure_authentication_token
def ensure_authentication_token
if authentication_token.blank?
self.authentication_token = generate_authentication_token
end
end
private
def generate_authentication_token
loop do
token = Devise.friendly_token
break token unless User.find_by(authentication_token: token)
end
end
Puis-je avoir les contrôleurs suivants:
api_controller.rb
class ApiController < ApplicationController
respond_to :json
skip_before_filter :authenticate_user!
protected
def user_params
params[:user].permit(:email, :password, :password_confirmation)
end
end
(À noter que mes application_controller
a la ligne before_filter :authenticate_user!
.)
api/sessions_controller.rb
class Api::SessionsController < Devise::RegistrationsController
prepend_before_filter :require_no_authentication, :only => [:create ]
before_filter :ensure_params_exist
respond_to :json
skip_before_filter :verify_authenticity_token
def create
build_resource
resource = User.find_for_database_authentication(
email: params[:user][:email]
)
return invalid_login_attempt unless resource
if resource.valid_password?(params[:user][:password])
sign_in("user", resource)
render json: {
success: true,
auth_token: resource.authentication_token,
email: resource.email
}
return
end
invalid_login_attempt
end
def destroy
sign_out(resource_name)
end
protected
def ensure_params_exist
return unless params[:user].blank?
render json: {
success: false,
message: "missing user parameter"
}, status: 422
end
def invalid_login_attempt
warden.custom_failure!
render json: {
success: false,
message: "Error with your login or password"
}, status: 401
end
end
api/registrations_controller.rb
class Api::RegistrationsController < ApiController
skip_before_filter :verify_authenticity_token
def create
user = User.new(user_params)
if user.save
render(
json: Jbuilder.encode do |j|
j.success true
j.email user.email
j.auth_token user.authentication_token
end,
status: 201
)
return
else
warden.custom_failure!
render json: user.errors, status: 422
end
end
end
Et dans config/routes.rb:
namespace :api, defaults: { format: "json" } do
devise_for :users
end
Je suis hors de ma profondeur un peu et je suis sûr qu'il y a quelque chose ici que mon futur moi allons regarder en arrière sur et grincer des dents (il y a habituellement). Certains douteux parties:
Tout d'abord, vous remarquerez qu' Api::SessionsController
hérite Devise::RegistrationsController
alors qu' Api::RegistrationsController
hérite ApiController
(j'ai aussi quelques autres contrôleurs, tels que Api::EventsController < ApiController
qui traitent de plus standard RESTE des trucs pour mes autres modèles et n'ont pas beaucoup de contact avec les Concevoir.) C'est un assez moches, mais je ne pouvais pas imaginer une autre façon d'obtenir l'accès aux méthodes j'ai besoin en Api::RegistrationsController
. Le tutoriel, j'ai lié ci-dessus a la ligne include Devise::Controllers::InternalHelpers
, mais ce module semble avoir été supprimé dans les versions plus récentes de Concevoir.
Deuxièmement, j'ai désactivé la protection CSRF avec la ligne, skip_before_filter :verify_authentication_token
. J'ai des doutes quant à savoir si c'est une bonne idée, je vois beaucoup de contradictoires ou difficiles à comprendre des conseils quant à savoir si JSON Api sont vulnérables à des attaques CSRF, mais l'ajout de cette ligne a été la seule façon que j'ai pu obtenir la fichue chose à travailler.
Troisièmement, je veux m'assurer de comprendre comment fonctionne l'authentification une fois qu'un utilisateur s'est connecté. Dire que j'ai un appel d'API GET /api/friends
qui renvoie une liste de l'utilisateur actuel amis. Si je comprends bien, l'application iOS devrait obtenir l'utilisateur authentication_token
de la base de données (qui est une valeur fixe pour chaque utilisateur qui ne change jamais??), puis le présenter comme un param avec chaque demande, par exemple, GET /api/friends?authentication_token=abcdefgh1234
, puis mon Api::FriendsController
pourrait faire quelque chose comme User.find_by(authentication_token: params[:authentication_token])
pour obtenir le current_user. Est-ce vraiment aussi simple, ou ai-je raté quelque chose?
Donc, pour toute personne qui a réussi à lire tout le chemin à la fin de cette grande question, merci pour votre temps! Pour résumer:
- Est-ce le système de connexion sécurisé? Ou est-il quelque chose que j'ai oublié ou mal compris, par exemple, lorsqu'il est livré à des attaques CSRF?
- Est ma compréhension de la façon d'authentifier les demandes une fois que les utilisateurs sont inscrits dans le bon? (Voir "enfin..." ci-dessus).
-
Est-il possible que ce code peut être enlevé ou rendu plus agréable? En particulier le design laid d'avoir un contrôleur hérite de l'
Devise::RegistrationsController
et les autres à partir d'ApiController
.
Merci!