2012-02-10 8 views
16

Questa è in realtà una domanda piuttosto semplice, ma non riesco a trovare la risposta. Nel Omniauth Overview on Github, v'è in realtà una spiegazione, ma io non capisco:Cosa fa ": evento =>: autenticazione"?

We pass the :event => :authentication to the sign_in_and_redirect method 
to force all authentication callbacks to be called. 

Ho già l'autenticazione a lavorare con un'azione simile a questo:

def facebook 
    authenticator = UserAuthenticator.new(request.env["omniauth.auth"], current_user) 

    if authenticator.user_authenticated? 
    sign_in_and_redirect authenticator.user, :event => :authentication 
    else 
    session["devise.oauth_data"] = request.env["omniauth.auth"] 
    redirect_to new_user_registration_url 
    end 
end 

Tutto quello che veramente voglio sapere è a cosa serve :event => :authentication?

risposta

20

Vorrei solo aiutare a capire la risposta. Ho seguito personalmente il codice sorgente, che mi aiuta a capire come funziona il parametro :event => :authentication. Spero che ti sia d'aiuto.

Quindi la tua domanda è: perché

passare il: event =>: l'autenticazione al metodo sign_in_and_redirect per forzare tutti i callback di autenticazione per essere chiamati.

quindi, possiamo tracciare la definizione.

# Sign in a user and tries to redirect first to the stored location and 
# then to the url specified by after_sign_in_path_for. It accepts the same 
# parameters as the sign_in method. 
def sign_in_and_redirect(resource_or_scope, *args) 
    options = args.extract_options! 
    scope = Devise::Mapping.find_scope!(resource_or_scope) 
    resource = args.last || resource_or_scope 
    sign_in(scope, resource, options) 
    redirect_to after_sign_in_path_for(resource) 
end 

e poi sign_in definire devise:

# All options given to sign_in is passed forward to the set_user method in warden. 
# The only exception is the :bypass option, which bypass warden callbacks and stores 
# the user straight in session. This option is useful in cases the user is already 
# signed in, but we want to refresh the credentials in session. 
# 
# Examples: 
# 
# sign_in :user, @user      # sign_in(scope, resource) 
# sign_in @user        # sign_in(resource) 
# sign_in @user, :event => :authentication # sign_in(resource, options) 
# sign_in @user, :bypass => true   # sign_in(resource, options) 
# 
def sign_in(resource_or_scope, *args) 
    options = args.extract_options! 
    scope = Devise::Mapping.find_scope!(resource_or_scope) 
    resource = args.last || resource_or_scope 

    expire_session_data_after_sign_in! 

    if options[:bypass] 
    warden.session_serializer.store(resource, scope) 
    elsif warden.user(scope) == resource && !options.delete(:force) 
    # Do nothing. User already signed in and we are not forcing it. 
    true 
    else 
    warden.set_user(resource, options.merge!(:scope => scope)) 
    end 
end 

Va bene, così :event => :authentication ora è passato a warden#set_user, allora la tua domanda diventare il motivo per cui

passare il: event =>: l'autenticazione al metodo sign_in_and_redirect per forzare la chiamata di tutti i callback di autenticazione.

# Manually set the user into the session and auth proxy 
# 
# Parameters: 
# user - An object that has been setup to serialize into and out of the session. 
# opts - An options hash. Use the :scope option to set the scope of the user, set the :store option to false to skip serializing into the session, set the :run_callbacks to false to skip running the callbacks (the default is true). 
# 
# :api: public 
def set_user(user, opts = {}) 
    scope = (opts[:scope] ||= @config.default_scope) 

    # Get the default options from the master configuration for the given scope 
    opts = (@config[:scope_defaults][scope] || {}).merge(opts) 
    opts[:event] ||= :set_user 
    @users[scope] = user 

    if opts[:store] != false && opts[:event] != :fetch 
    options = env[ENV_SESSION_OPTIONS] 
    options[:renew] = true if options 
    session_serializer.store(user, scope) 
    end 

    run_callbacks = opts.fetch(:run_callbacks, true) 
    manager._run_callbacks(:after_set_user, user, self, opts) if run_callbacks 

    @users[scope] 
end 

opta [: evento] può essere [:set_user, :fetch, :authentication]

# Hook to _run_callbacks asserting for conditions. 
def _run_callbacks(kind, *args) #:nodoc: 
    options = args.last # Last callback arg MUST be a Hash 

    send("_#{kind}").each do |callback, conditions| 
    invalid = conditions.find do |key, value| 
     value.is_a?(Array) ? !value.include?(options[key]) : (value != options[key]) 
    end 

    callback.call(*args) unless invalid 
    end 
end 

# A callback hook set to run every time after a user is set. 
# This callback is triggered the first time one of those three events happens 
# during a request: :authentication, :fetch (from session) and :set_user (when manually set). 
# You can supply as many hooks as you like, and they will be run in order of decleration. 
# 
# If you want to run the callbacks for a given scope and/or event, you can specify them as options. 
# See parameters and example below. 
# 
# Parameters: 
# <options> Some options which specify when the callback should be executed 
# scope - Executes the callback only if it maches the scope(s) given 
# only - Executes the callback only if it matches the event(s) given 
# except - Executes the callback except if it matches the event(s) given 
# <block> A block where you can set arbitrary logic to run every time a user is set 
# Block Parameters: |user, auth, opts| 
#  user - The user object that is being set 
#  auth - The raw authentication proxy object. 
#  opts - any options passed into the set_user call includeing :scope 
# 
# Example: 
# Warden::Manager.after_set_user do |user,auth,opts| 
#  scope = opts[:scope] 
#  if auth.session["#{scope}.last_access"].to_i > (Time.now - 5.minutes) 
#  auth.logout(scope) 
#  throw(:warden, :scope => scope, :reason => "Times Up") 
#  end 
#  auth.session["#{scope}.last_access"] = Time.now 
# end 
# 
# Warden::Manager.after_set_user :except => :fetch do |user,auth,opts| 
#  user.login_count += 1 
# end 
# 
# :api: public 
def after_set_user(options = {}, method = :push, &block) 
    raise BlockNotGiven unless block_given? 

    if options.key?(:only) 
    options[:event] = options.delete(:only) 
    elsif options.key?(:except) 
    options[:event] = [:set_user, :authentication, :fetch] - Array(options.delete(:except)) 
    end 

    _after_set_user.send(method, [block, options]) 
end 

così,

# after_authentication is just a wrapper to after_set_user, which is only invoked 
# when the user is set through the authentication path. The options and yielded arguments 
# are the same as in after_set_user. 
# 
# :api: public 
def after_authentication(options = {}, method = :push, &block) 
    after_set_user(options.merge(:event => :authentication), method, &block) 
end 
12

Passando :event => :authentication provoca Warden (sottostante Devise) per attivare qualsiasi callback definiti con:

Warden::Manager.after_authentication do |user,auth,opts| 
    # Code triggered by authorization here, for example: 
    user.last_login = Time.now 
end 

Se non si utilizzano i callback after_authentication e si è certi che anche le librerie non lo siano, non è di alcuna utilità immediata per l'utente. Dato che si tratta di un evento di autenticazione, vorrei lasciarlo, ora che sai per cosa è potenzialmente utile.