Что делает ": event =>: authentication"? - PullRequest
17 голосов
/ 10 февраля 2012

На самом деле это довольно простой вопрос, но я не могу найти ответ.В Omniauth Overview на Github есть объяснение, но я его не понимаю:

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

У меня уже есть аутентификация, работающая с использованием действия, подобного этому:

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

Все, что я действительно хочу знать, это то, что хорошо :event => :authentication для?

Ответы [ 2 ]

21 голосов
/ 18 октября 2012

Я просто хотел бы помочь выяснить ответ.Я сам отслеживал исходный код, который помогает мне понять, как работает параметр :event => :authentication.Я надеюсь, что это также поможет вам.

Итак, ваш вопрос состоит в том, почему

передает аутентификацию: event =>: методу sign_in_and_redirect для принудительного вызова всех обратных вызовов аутентификации.

затем мы можем отследить определение.

# 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

и затем sign_in определить в 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

Хорошо, поэтому :event => :authentication теперь передается вwarden#set_user, тогда возникает вопрос, почему

передает аутентификацию: event =>: методу sign_in_and_redirect для принудительного вызова всех обратных вызовов аутентификации.

# 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

opts [: event] может быть [: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

,

# 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
13 голосов
/ 15 ноября 2012

Передача :event => :authentication заставляет Warden (лежащий в основе Devise) запускать любые обратные вызовы, определенные с помощью:

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

Если вы не используете никаких обратных вызовов after_authentication, и вы уверены, что ваши библиотеки не 'Это тоже не имеет к вам непосредственного отношения.Поскольку это событие аутентификации, я бы оставил его там, теперь, когда вы знаете, для чего оно потенциально полезно.

...