1

HintergrundOmniahuth custom `callback_path` macht` env ['omniauth.auth'] `return nil. Versuchte wenige Ansätze fruchtbar zu einem gewissen Grad, aber

Meine Anwendung am Ende andernfalls erfordert mich zu zwei verschiedenen Facebook-Apps für verschiedene Zwecke zu verbinden und für die ich weiter unten Code.

Problem

Wenn eine benutzerdefinierte callback_path Verwendung wie in Methode facebook_opts_for_social_sharing unten, in den Handler d.h. Rückruf gezeigt in meinem ExternalApiAuthController#create_social_sharing_auth_account Aktion request.env['omniauth.auth'] als NIL zurückgegeben. Ein ähnliches Problem wird in intridea/omniauth Repo gemeldet.

/config/routes.rb

get '/auth/:provider/callback', to: 'external_api_auth#create' 
    get '/auth/:provider/social_sharing/callback', to: 'external_api_auth#create_social_media_platform_account', as: :social_sharing_auth 
    get '/auth/failure', to: 'external_api_auth#failure' 

/app/controllers/external_api_auth_controller.rb

class ExternalApiAuthController 
    # GET /auth/failure 
    def failure 
    end 

    # GET /auth/:provider/callback 
    def create 
    end 

    # GET /auth/:provider/social_sharing/callback 
    def create_social_media_platform_account 
    end 
    end 

/config/initializers/omniauth.rb

def provider_facebook 
     'facebook' 
    end 

    def facebook_opts 
     my_model_obj = MyModelService.find_by_provider_name(provider_facebook) 

     return unless my_model_obj.present? 

     app_details_hash = my_model_obj.application_details 
     client_id = app_details_hash[:client_id] 
     client_secret = app_details_hash[:client_secret] 

     return if client_id.blank? || client_secret.blank? 

     { 
     client_id: client_id, 
     client_secret: client_secret, 
     scope: 'email,manage_pages,publish_pages', 
     display: 'popup' 
     } 
    end 

    def facebook_opts_for_social_sharing 
     my_model_obj = MyAnotherModelService.find_by_internal_name(provider_facebook) 

     return unless my_model_obj.present? 

     app_details_hash = my_model_obj.application_details 
     client_id = app_details_hash[:client_id] 
     client_secret = app_details_hash[:client_secret] 

     return if client_id.blank? || client_secret.blank? 

     { 
     client_id: client_id, 
     client_secret: client_secret, 
     scope: 'email,manage_pages,publish_pages', 
     display: 'popup', 
     callback_path: ExternalApiAuthUrl.sharing_auth_callback_path(provider: provider_facebook) 
     } 
    end 

    SETUP_PROC = lambda do |env| 
     strategy_instance = env['omniauth.strategy'] 
     provider_name = provider_name_from_oauth_strategy_class(strategy_instance.class) 

     request = Rack::Request.new(env) 

     is_social_sharing_auth = false 

     auth_purpose = request.params[ExternalApiAuthUrl::AUTH_PURPOSE_PARAM_NAME] 
     if ExternalApiAuthUrl.is_auth_purpose_sharing?(auth_purpose: auth_purpose) 
     is_social_sharing_auth = true 
     end 

     opts = case provider_name.downcase.underscore 
       when 'facebook' 
       (is_social_sharing_auth ? facebook_opts_for_sharing : facebook_opts) 
       else 
       nil 
      end 

     if opts.present? 
     env['omniauth.strategy'].options.merge!(opts) 
     end 
    end 

    OmniAuth.config.logger = Rails.logger 

    OmniAuth.config.on_failure do |env| 
     ..... 
     ..... 
    end 

    Rails.application.config.middleware.use OmniAuth::Builder do 
     # Reference: https://github.com/intridea/omniauth/wiki/Setup-Phase 
     provider :facebook, setup: SETUP_PROC 
    #end 

Mit diesem Code wird die callback_path wird korrekt während Anfrage Phase. Sobald jedoch die Anfrage-Phase beendet und initiiert Redirect, nur die OmniAuth::Strategies::Facebook.default options werden von OmniAuth::Strategy Instanz verwendet werden. Da diese Optionen enthalten nicht die callback_path (nach Redirect initiiert wurde) on_callback_path? während Auswertung folgende Linie return callback_call if on_callback_path? immer false zurückgibt und damit Rückruf Phase nie eine Chance zur Ausführung kommen.

Ansatz 1

Um diese Einschränkung zu bekommen ich in jeder Phase einen Ansatz versucht, die callback_path in OmniAuth::Strategies::Facebook.default options , so dass wird sie abgeholt zu senden. Daher, anstatt sie durch den Code in SETUP_PROC wie facebook_opts_for_social_sharing in Verfahren der Weitergabe, geben ich es in folgender Weise also ging sie als Option OmniAuth::Builder#provider Methodenaufruf:

Rails.application.config.middleware.use OmniAuth::Builder do provider :facebook, setup: SETUP_PROC, callback_path: ExternalApiAuthUrl.sharing_auth_callback_path(provider: provider_facebook) end

Und es aktualisiert SETUP_PROC machen arbeiten aussehen wie

SETUP_PROC = lambda do |env| 
     strategy_instance = env['omniauth.strategy'] 
     provider_name = provider_name_from_oauth_strategy_class(strategy_instance.class) 

     request = Rack::Request.new(env) 

     is_social_sharing_auth = false 

     auth_purpose = request.params[ExternalApiAuthUrl::AUTH_PURPOSE_PARAM_NAME] 
     if ExternalApiAuthUrl.is_auth_purpose_sharing?(auth_purpose: auth_purpose) 
     is_social_sharing_auth = true 
     elsif (request.path_info.casecmp(ExternalApiAuthUrl.social_sharing_auth_callback_path(provider: provider_name)) == 0) 
     is_social_sharing_auth = true 
     end 

     opts = case provider_name.downcase.underscore 
       when 'facebook' 
       (is_social_sharing_auth ? facebook_opts_for_sharing : facebook_opts) 
       else 
       nil 
      end 

     unless is_social_sharing_auth 
     env['omniauth.strategy'].options.delete(:callback_path) 
     end 

     if opts.present? 
     env['omniauth.strategy'].options.merge!(opts) 
     end 
    end 

jedoch macht dies die benutzerdefinierte callback_path Szenario arbeiten, aber die Standard callback_path/auth/facebook/callback Szenario schlägt fehl, da die callback_path-Option, die einen benutzerdefinierten Rückrufpfad enthält, immer in OmniAuth::Strategy Instanz verfügbar ist.

Ansatz 2

So um die Begrenzung von Ansatz 1 ich einen anderen Ansatz versucht, eine Middleware zu verwenden, die auf der path_info Antrag basiert gestellt zu bekommen und params die Strategie Middleware mit der gewünschten Optionen aufruft.

/app/middleware/omniauth_builder_setup.rb

class OmniauthBuilderSetup 
     def initialize(app) 
     @app = app 
     end 

     def call(env) 
     request = Rack::Request.new(env) 

     Rails.logger.debug ">>>>>>>>>>>>> OmniauthBuilderSetup @app: #{@app.inspect}" 

     provider_name = provider_name(request.path_info) 

     unless provider_name 
      status, headers, response = @app.call(env) 
      return [status, headers, response] 
     end 

     is_social_sharing_auth = false 

     auth_purpose = request.params[ExternalApiAuthUrl::AUTH_PURPOSE_PARAM_NAME] 
     if ExternalApiAuthUrl.is_auth_purpose_reviews_social_sharing?(auth_purpose: auth_purpose) 
      is_social_sharing_auth = true 
     elsif (request.path_info.casecmp(ExternalApiAuthUrl.social_sharing_auth_callback_path(provider: provider_name)) == 0) 
      is_social_sharing_auth = true 
     end 

     if is_social_sharing_auth 
      middleware_instance = omniauth_strategy_middleware(provider_name, setup: SETUP_PROC, callback_path: ExternalApiAuthUrl.social_sharing_auth_callback_path(provider: provider_name)) 
     else 
      middleware_instance = omniauth_strategy_middleware(provider_name, setup: SETUP_PROC) 
     end 

     Rails.logger.debug ">>>>>>>>>>>>> OmniauthBuilderSetup middleware_instance: #{middleware_instance.inspect}" 

     @app = middleware_instance 

     status, headers, response = @app.call(env) 

     [status, headers, response] 
     end 

     private 

     def provider_name_regex 
     # matches 
     # /auth/facebook 
     # /auth/facebook/callback 
     # /auth/facebook?auth_purpose=social_sharing 

     /\A\/auth\/(facebook|twitter)(?:((\/.*)|(\?.+=.+))?)\z/ 
     end 

     def provider_name(path_info) 
     match_data = path_info.match(provider_name_regex) 

     return if match_data.nil? 

     match_data.captures.first 
     end 

     def omniauth_strategy_middleware(klass, *args, &block) 
     if klass.is_a?(Class) 
      middleware = klass 
     else 
      begin 
      middleware = OmniAuth::Strategies.const_get("#{OmniAuth::Utils.camelize(klass.to_s)}") 
      rescue NameError 
      raise(LoadError.new("Could not find matching strategy for #{klass.inspect}. You may need to install an additional gem (such as omniauth-#{klass}).")) 
      end 
     end 

     args.last.is_a?(Hash) ? args.push({}.merge(args.pop)) : args.push({}) 
     middleware.new(middleware, *args, &block) 
     end 
    end 

/config/application.rb

.... 

    config.middleware.use "OmniauthBuilderSetup" 
    .... 

/config/initializers/omniauth.rb (Kommentar gesetzt use OmniAuth::Builder)

.... 
    ...... 
    ..... 

    #Rails.application.config.middleware.use OmniAuth::Builder do 
    # provider :facebook, setup: SETUP_PROC, callback_path: ExternalApiAuthUrl.reviews_social_sharing_auth_callback_path(provider: provider_facebook) 
    #end 

Mit dieser Middleware-Methode wird die Callback-Phase in beiden Szenarien initiiert, d. H. Wenn der Standard-Callback-Pfad /auth/facebook/callback und ein benutzerdefinierter Callback-Pfad /auth/facebook/social_sharing/callback verwendet wird. Aber während Callback-Phase aber es funktioniert nicht mit folgenden Fehler:

 undefined method `call' for OmniAuth::Strategies::Facebook:Class Did you mean? caller 

Ich habe einige Protokollanweisungen in OmniAuth::Strategy und die folgenden Protokolle wurden erzeugt.

 Started GET "/auth/facebook" for 127.0.0.1 at 2016-07-28 10:28:23 +0530 
     >>>>>>>>>>>>> OmniauthBuilderSetup @app: #<ActionDispatch::Routing::RouteSet:0x000000073a64c8> 
     >>>>>>>>>>>>> OmniauthBuilderSetup middleware_instance: #<OmniAuth::Strategies::Facebook> 
     >>>>>>>>>>>>> OmniauthBuilderSetup @app: #<OmniAuth::Strategies::Facebook> 
     (facebook) Setup endpoint detected, running now. 
     (facebook) Request phase initiated. 


     Started GET "/auth/facebook/callback?code=AQDxel76u_UvtTeSHUw3CzMpA98KTI4V_75qhxV5TGD7rdGcyeCX-FS1nrrlo-EAezZXUPdH9cAC5h4c1xlqoIL7UZ2WLDfXHG4GHWZTEGYHzH7QURNSkrjvDoBNWV90E83f_R6RURl1POsq8ZhmQOFD5YGXRxosiVx4Sof8_vqJZ5UT2S5SFbmVLEtaZZacJDqEbWjNKBrYdrZauuqCS91lEw6Lrz5U5rA2eOmmygAiBwso-cnmOuRu-PptwtIbBL5zw5hPOANQskIFHL-lfbobZYBwy_NsY8Nf-HsJauuymSmtfsQ28UaPlkox9vSinqDAHYhW1ltBXrOX_7P4HfBr&state=3831c127892242fb43aaa2ebfe37cac9e0cd2c8dbea06f3e" for 127.0.0.1 at 2016-07-28 10:28:29 +0530 
     >>>>>>>>>>>>> OmniauthBuilderSetup @app: #<OmniAuth::Strategies::Facebook> 
     >>>>>>>>>>>>> OmniauthBuilderSetup middleware_instance: #<OmniAuth::Strategies::Facebook> 
     >>>>>>>>>>>>> OmniauthBuilderSetup @app: #<OmniAuth::Strategies::Facebook> 
     >>>>>>>>>>>>> OmniAuth::Strategy call!(env) @app OmniAuth::Strategies::Facebook 
     >>>>>>>>>>>>> OmniAuth::Strategy call!(env) options #<OmniAuth::Strategy::Options access_token_options=#<OmniAuth::Strategy::Options header_format="OAuth %s" param_name="access_token"> auth_token_params=#<OmniAuth::Strategy::Options> authorize_options=[:scope, :display, :auth_type] authorize_params=#<OmniAuth::Strategy::Options> client_id=nil client_options=#<OmniAuth::Strategy::Options authorize_url="https://www.facebook.com/dialog/oauth" site="https://graph.facebook.com" token_url="oauth/access_token"> client_secret=nil name="facebook" provider_ignores_state=false setup=#<Proc:[email protected]/jwork/ruby/ror_projects/Reviewgo-JonathanSmith/reviewgo/config/initializers/omniauth.rb:76 (lambda)> skip_info=false token_options=[] token_params=#<OmniAuth::Strategy::Options parse=:query>> 
     >>>>>>>>>>>>> OmniAuth::Strategy call!(env) class: OmniAuth::Strategies::Facebook 
     >>>>>>>>>>>>>>OmniAuth::Strategy call!(env) current_path: /auth/facebook/callback 
     >>>>>>>>>>>>>>OmniAuth::Strategy call!(env) on_callback_path?: true 
     (facebook) Setup endpoint detected, running now. 
     (facebook) Callback phase initiated. 

     NoMethodError (undefined method `call' for OmniAuth::Strategies::Facebook:Class 
     Did you mean? caller): 
     app/middleware/omniauth_builder_setup.rb:61:in `call' 

Wenn Sie während der Callback-Phase in meiner Middleware bemerken die @app hält eine Instanz von OmniAuth :: Strategien :: Facebook aber sobald die Steuerung erreicht OmniAuth :: Strategie @app in OmniAuth :: Strategie-Instanz bezieht sich auf Klasse OmniAuth::Strategies::Facebook.

 >>>>>>>>>>>>> OmniauthBuilderSetup @app: #<OmniAuth::Strategies::Facebook> 
     >>>>>>>>>>>>> OmniauthBuilderSetup middleware_instance: #<OmniAuth::Strategies::Facebook> 
     >>>>>>>>>>>>> OmniauthBuilderSetup @app: #<OmniAuth::Strategies::Facebook> 
     >>>>>>>>>>>>> OmniAuth::Strategy call!(env) @app OmniAuth::Strategies::Facebook 

Ich bin sicher, dass es ein Problem mit meiner Middleware gibt. Ich habe Middlewares vorher nicht benutzt, also verstehe dieses @app Konzept nicht. Versucht, auf wenige Ressourcen im Web zu verweisen, um es zu erfassen, aber keinen Erfolg.

  1. Kann mir bitte jemand helfen, meine Middleware zu reparieren, damit sie in der gewünschten Weise funktioniert?

  2. Wenn möglich, bitte versuchen Sie, mir das Konzept von @app zu verstehen und den Status, Header und Körper Werte @ app.call (env) sollte zurückgeben. Für z.B. In meinem Fall brauche ich die Middleware, um nur dann fortzufahren, wenn sie den gewünschten Omniauth-Pfaden entspricht. Wenn nicht, sollte es überspringen und vorwärts gehen, ohne zu stören. Ich kann dieses Verhalten nicht erreichen.

P.S. Ich kämpfe um diese Einschränkung der vergangenen 2 Tage und mit all den Details hier, meine Ergebnisse, meine Ansätze Ich hoffe, dass jemand aus der Gemeinschaft wird definitiv kommen, um mich bei der Lösung meines Problems zu führen.

Danke.

Antwort

1

Wooohhoooooooooooo endlich gelöst. Ich habe das Problem in meiner Middleware behoben und es hat angefangen zu arbeiten.Danke an this Beitrag und seine angenommene Antwort, die mich in das Finden des Problems in meiner Middleware und das Beheben von es geführt hat.

Müssen Code in folgenden Methoden ändern. Im Folgenden finden Sie die vorherige Version gezeigt, wie in meinem Beitrag oben gezeigt wird:

def call(env) 
    request = Rack::Request.new(env) 

    Rails.logger.debug ">>>>>>>>>>>>> OmniauthBuilderSetup @app: #{@app.inspect}" 

    provider_name = provider_name(request.path_info) 

    unless provider_name 
     status, headers, response = @app.call(env) 
     return [status, headers, response] 
    end 

    is_social_sharing_auth = false 

    auth_purpose = request.params[ExternalApiAuthUrl::AUTH_PURPOSE_PARAM_NAME] 
    if ExternalApiAuthUrl.is_auth_purpose_reviews_social_sharing?(auth_purpose: auth_purpose) 
     is_social_sharing_auth = true 
    elsif (request.path_info.casecmp(ExternalApiAuthUrl.social_sharing_auth_callback_path(provider: provider_name)) == 0) 
     is_social_sharing_auth = true 
    end 

    if is_social_sharing_auth 
     middleware_instance = omniauth_strategy_middleware(provider_name, setup: SETUP_PROC, callback_path: ExternalApiAuthUrl.social_sharing_auth_callback_path(provider: provider_name)) 
    else 
     middleware_instance = omniauth_strategy_middleware(provider_name, setup: SETUP_PROC) 
    end 

    Rails.logger.debug ">>>>>>>>>>>>> OmniauthBuilderSetup middleware_instance: #{middleware_instance.inspect}" 

    @app = middleware_instance 

    status, headers, response = @app.call(env) 

    [status, headers, response] 
    end 


    def omniauth_strategy_middleware(klass, *args, &block) 
    if klass.is_a?(Class) 
     middleware = klass 
    else 
     begin 
     middleware = OmniAuth::Strategies.const_get("#{OmniAuth::Utils.camelize(klass.to_s)}") 
     rescue NameError 
     raise(LoadError.new("Could not find matching strategy for #{klass.inspect}. You may need to install an additional gem (such as omniauth-#{klass}).")) 
     end 
    end 

    args.last.is_a?(Hash) ? args.push({}.merge(args.pop)) : args.push({}) 
    middleware.new(middleware, *args, &block) 
    end 

Modified Code:

def call(env) 
    request = Rack::Request.new(env) 

    Rails.logger.debug ">>>>>>>>>>>>> OmniauthBuilderSetup @app: #{@app.inspect}" 

    provider_name = provider_name(request.path_info) 

    unless provider_name 
     status, headers, response = @app.call(env) 
     return [status, headers, response] 
    end 

    is_social_sharing_auth = false 

    auth_purpose = request.params[ExternalApiAuthUrl::AUTH_PURPOSE_PARAM_NAME] 
    if ExternalApiAuthUrl.is_auth_purpose_reviews_social_sharing?(auth_purpose: auth_purpose) 
     is_social_sharing_auth = true 
    elsif (request.path_info.casecmp(ExternalApiAuthUrl.social_sharing_auth_callback_path(provider: provider_name)) == 0) 
     is_social_sharing_auth = true 
    end 

    if is_social_sharing_auth 
     middleware_instance = omniauth_strategy_middleware(provider_name, setup: SETUP_PROC, callback_path: ExternalApiAuthUrl.social_sharing_auth_callback_path(provider: provider_name)) 
    else 
     middleware_instance = omniauth_strategy_middleware(provider_name, setup: SETUP_PROC) 
    end 

    Rails.logger.debug ">>>>>>>>>>>>> OmniauthBuilderSetup middleware_instance: #{middleware_instance.inspect}" 

    status, headers, response = middleware_instance.call(env) # <<<<<--------- Changed here 

    [status, headers, response] 
    end 


    def omniauth_strategy_middleware(klass, *args, &block) 
    if klass.is_a?(Class) 
     middleware = klass 
    else 
     begin 
     middleware = OmniAuth::Strategies.const_get("#{OmniAuth::Utils.camelize(klass.to_s)}") 
     rescue NameError 
     raise(LoadError.new("Could not find matching strategy for #{klass.inspect}. You may need to install an additional gem (such as omniauth-#{klass}).")) 
     end 
    end 

    args.last.is_a?(Hash) ? args.push({}.merge(args.pop)) : args.push({}) 
    middleware.new(@app, *args, &block) # <<<<<--------- Changed here 
    end 

Update: einen Kern an https://gist.github.com/jiggneshhgohel/4a79aa26cb628533fe132295cffc45b2 Erstellt den gesamten Code enthält. Hoffe es hilft jemandem wie mir und kann Zeit sparen.

Danke.