Хорошо, наконец-то, получил это на работу.Сообщаемая ошибка была просто странной вещью с обработкой ошибок и не имела ничего общего с реальной проблемой.Проблема заключалась в том, что гем oauth2 является общим, и вам нужно сделать несколько вещей, чтобы он работал с Facebook.Эти вещи, которые вы должны сделать, отличаются от readme (для получения дополнительной информации см. Выпуски 70 и 75 на github)
Прежде чем создавать свой клиент, вы должны зарегистрировать парсер для ответа на Facebook:
OAuth2::Response.register_parser(:facebook, 'text/plain') do |body|
token_key, token_value, expiration_key, expiration_value = body.split(/[=&]/)
{token_key => token_value, expiration_key => expiration_value, :mode => :query, :param_name => 'access_token'}
end
Вы также должны установить URL-адрес токена для клиента при создании:
@client = OAuth2::Client.new(ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET'], {:site => 'https://graph.facebook.com', :token_url => '/oauth/access_token'})
Когда oauth получает ответ, он использует синтаксический анализатор, который вы указали ему использовать для анализа ответа вхешСинтаксический анализатор custom: facebook гарантирует, что хеш содержит токен доступа и строку с истекающим сроком действия, и указывает ему использовать режим запроса, а имя параметра - access_token.Без режима и param_name клиент Oauth будет пытаться отправить токен доступа в заголовке, а не в строке запроса при доступе к ресурсам.Facebook ожидает, что токен доступа будет в URL.Без param_name клиент oauth отправляет его как https://graph.facebook.com/bearer_token=ABC. С параметром param_name это https://graph.facebook.com/access_token=ABC
Наконец, когда вы создаете свой объект AccessToken, обязательно сообщите ему использовать ваш собственный анализатор, например, так:
token = client.auth_code.get_token(@data[:code], {:redirect_uri => redirect_uri, :parsed => :facebook})
В целом это выглядит так:
require 'sinatra'
require 'oauth2'
require 'json'
class App < Sinatra::Base
configure do
set :views_folder, File.join($BP, 'views')
set :public_folder, File.join($BP, 'public')
end
before do
@data = JSON.parse(request.env["rack.input"].read) if request.request_method =~ /POST|PUT|DELETE/i
@data = params if request.request_method == 'GET'
end
before do
pass if (request.path_info == '/auth/facebook' || request.path_info == '/auth/facebook/callback')
redirect to('/auth/facebook') unless self.logged_in
end
get "/" do
request.request_method
end
def client
if !@client
OAuth2::Response.register_parser(:facebook, 'text/plain') do |body|
token_key, token_value, expiration_key, expiration_value = body.split(/[=&]/)
{token_key => token_value, expiration_key => expiration_value, :mode => :query, :param_name => 'access_token'}
end
@client = OAuth2::Client.new(ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET'], {:site => 'https://graph.facebook.com', :token_url => '/oauth/access_token'})
end
@client
end
get '/auth/facebook' do
redirect client.auth_code.authorize_url(
:redirect_uri => redirect_uri,
:scope => 'email'
)
end
get '/auth/facebook/callback' do
token = client.auth_code.get_token(@data[:code], {:redirect_uri => redirect_uri, :parsed => :facebook})
user = token.get('/me').parsed
create_user user unless user_exists user
end
def redirect_uri
uri = URI.parse(request.url)
uri.path = '/auth/facebook/callback'
uri.query = nil
uri.to_s
end
end