2012-01-14 66 views
4

我可以導航到成功重定向到Facebook的主要url。我授予權限,並且我被重定向回到了回調網址。如果這個url只是簡單地返回類似'hello'的東西,那麼它工作正常並沒有錯誤。但撥打token = client.auth_code.get_token(@data[:code], :redirect_uri => redirect_uri)會導致錯誤。Sinatra使用gem oauth2登錄到Facebook OAuth 2.0

回答

6

好吧終於得到了這個工作。被報告的錯誤是錯誤處理的一些奇怪的事情,並且與實際問題無關。問題是,oauth2寶石是通用的,你必須花費一些東西才能使它與Facebook一起工作。這些是你必須做的自述不同的東西(見GitHub上的問題70和75獲取更多信息)

您創建客戶端之前,你必須爲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 

您還可以設置客戶端的令牌網址上創造:

@client = OAuth2::Client.new(ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET'], {:site => 'https://graph.facebook.com', :token_url => '/oauth/access_token'}) 

當OAuth的接收的響應,它使用你告訴它使用解析響應到一個哈希解析器。自定義:Facebook解析器確保哈希包含訪問令牌和過期字符串,並告訴它使用查詢模式,並且參數名稱爲access_token。如果沒有模式和param_name,則在訪問資源時,Oauth客戶端將嘗試在頭中而不是查詢字符串中發送訪問令牌。 Facebook期望訪問令牌位於網址中。如果沒有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 [email protected] 
     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 
+0

如果任何人看到最佳做法違規,請讓我知道即時通訊設法得到更好的 – chris 2012-01-14 23:45:16

+0

我會考慮在路線之前分組你的幫手方法,但除此之外,這對我來說看起來不錯。我正要着手學習如何自己做這個,所以謝謝你讓我困惑不已:-) – 2012-01-16 22:13:10