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.
Kann mir bitte jemand helfen, meine Middleware zu reparieren, damit sie in der gewünschten Weise funktioniert?
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.