2012-02-10 31 views
16

Đây thực sự là một câu hỏi khá đơn giản nhưng tôi dường như không thể tìm thấy câu trả lời. Trong Omniauth Overview on Github, có thực sự là một lời giải thích nhưng tôi không nhận được nó:": event =>: authentication" làm gì?

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

Tôi đã có chứng thực làm việc sử dụng một hành động tương tự với trang này:

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 

Tất cả tôi thực sự muốn biết những gì tốt là :event => :authentication cho?

Trả lời

20

Tôi chỉ muốn giúp tìm ra câu trả lời. Tôi đã tự theo dõi mã nguồn, giúp tôi hiểu cách tham số :event => :authentication hoạt động. Tôi hy vọng nó cũng giúp bạn.

Vì vậy, câu hỏi của bạn là lý do tại sao

vượt qua: sự kiện =>: xác thực với phương pháp sign_in_and_redirect để buộc tất cả các callbacks xác thực để được gọi.

khi đó, chúng tôi có thể theo dõi định nghĩa.

# 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 

và sau đó sign_in xác định trong 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 

Được rồi, vì vậy :event => :authentication hiện đang truyền cho warden#set_user, Sau đó, câu hỏi của bạn trở thành lý do tại sao

vượt qua: sự kiện =>: xác thực với phương thức sign_in_and_redirect để buộc tất cả các cuộc gọi lại xác thực được gọi.

# 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 [: Sự kiện] có thể [: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 

vậy,

# 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

Đi qua :event => :authentication gây Warden (cơ bản lập mưu) để kích hoạt bất kỳ callbacks định nghĩa với:

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

Nếu bạn không sử dụng bất kỳ cuộc gọi lại nào là after_authentication và bạn chắc chắn thư viện của mình cũng không phải là thư viện thì bạn không thể sử dụng ngay lập tức. Vì nó là một sự kiện xác thực, tôi sẽ để nó vào, bây giờ bạn đã biết nó có thể hữu ích cho cái gì.