2012-04-20 31 views
22

Piszę aplikację Rails, która wykorzystuje omniauth-facebook do uwierzytelnienia użytkownika przed FB (i do uzyskania tokenu dostępu do OAuth FB dla użytkownika). Następnie aplikacja wykorzystuje Koala do wykonywania różnych wywołań interfejsu API FB GraphGeG za pomocą zapisanego tokenu OAuth.Przedawnienie i odnowienie tokena Facebooka, z Koala i omniauthem-facebookiem

Aktualizuję zapisany token przy każdym ponownym uwierzytelnianiu użytkownika (zazwyczaj po zalogowaniu się do mojej aplikacji). Mimo to zapisany token traci ważność (lub w inny sposób traci ważność) od czasu do czasu.

Jaka jest najlepsza praktyka w zakresie ochrony przed błędami auth i aktualizowania tokena podczas korzystania z Koali?

Czy wszystkie połączenia powinny być pakowane w bloki start/rescue, z obsługą wyjątków, która ponownie uwierzytelnia użytkownika przed FB?

Czy jest jakiś sposób (za pomocą Koali), aby skorzystać z procesu "rozszerzania tokenów dostępu" opisanego jako here? Jeśli nie, czy istnieją najlepsze praktyki dotyczące pisania własnego kodu, aby samemu wyodrębnić nowy token z połączenia Koala?

Odpowiedz

16

To, co mam, to filtr before_vilter uruchamiany na każdej stronie wymagającej aktywnej sesji na Facebooku. Coś takiego powinno zadziałać:

before_filter :reconnect_with_facebook 
    def reconnect_with_facebook 
    if current_account && current_account.token_expired?(session[:fb]["expires"]) 

    # re-request a token from facebook. Assume that we got a new token so 
    # update it anyhow... 
    session[:return_to] = request.env["REQUEST_URI"] unless request.env["REQUEST_URI"] == facebook_request_path 
    redirect_to(with_canvas(facebook_request_path)) and return false 
    end 
end 

Token_expired? metoda wygląda następująco:

def token_expired?(new_time = nil) 
    expiry = (new_time.nil? ? token_expires_at : Time.at(new_time)) 
    return true if expiry < Time.now ## expired token, so we should quickly return 
    token_expires_at = expiry 
    save if changed? 
    false # token not expired. :D 
end 
+0

Dzięki za odpowiedź. Gdzie/jak sesja [: fb] ["wygasa"] jest ustawiona? Używasz go w swojej metodzie reconnect_with_facebook powyżej. –

+0

Ustawiam to, gdy ktoś pierwszy raz zaloguje się, aby utworzyć sesję. Wszystkie inne połączenia są uznawane za "ponowne połączenia". Dzięki temu uzyskasz – heavysixer

+0

. Zaimplementowałem nieco inaczej, ale było to pomocne w doprowadzeniu mnie na właściwą drogę. –

16

natknąłem this post który dopasowuje kod z Railscast on Facebook aby pokazać w jaki sposób można wymieniać token krótkotrwały do ​​60 dnia:

user.rb

def self.from_omniauth(auth) 

    # immediately get 60 day auth token 
    oauth = Koala::Facebook::OAuth.new(ENV["FACEBOOK_APP_ID"], ENV["FACEBOOK_SECRET"]) 
    new_access_info = oauth.exchange_access_token_info auth.credentials.token 

    new_access_token = new_access_info["access_token"] 
    # Facebook updated expired attribute 
    new_access_expires_at = DateTime.now + new_access_info["expires_in"].to_i.seconds 

    where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user| 
     user.provider = auth.provider 
     user.uid = auth.uid 
     user.name = auth.info.name 
     user.image = auth.info.image 
     user.email = auth.info.email 
     user.oauth_token = new_access_token #originally auth.credentials.token 
     user.oauth_expires_at = new_access_expires_at #originally Time.at(auth.credentials.expires_at) 
     user.save! 
    end 
    end 
+0

Dzięki za fragment kodu! – okysabeni

+0

Dzięki temu jest to dobra metoda. Zajęło mi trochę czasu, aby dowiedzieć się, dlaczego moje testy narzekają na typ "Koala :: Facebook :: OAuthTokenRequestError: typu: OAuthException, kod: 101, komunikat: Brak parametru client_id. [HTTP 400] '. W końcu zdałem sobie sprawę, że nie zdefiniowałem 'ENV [" FACEBOOK_APP_ID "]' lub 'ENV [" FACEBOOK_SECRET "]' dla mojego środowiska testowego w 'secrets.yml'. – DazBaldwin

0

Możesz zrobić coś takiego, sprawdzając, czy hasło dostępu wygasło i wygenerować kolejne.

%w[facebook].each do |provider| 
    scope provider, -> { where(provider: provider) } 
end 

def client 
    send("#{provider}_client") 
end 

def expired? 
    expires_at? && expires_at <= Time.zone.now 
end 

def access_token 
    send("#{provider}_refresh_token!", super) if expired? 
    super 
end 

def facebook_refresh_token!(token) 
    new_token_info = 
    Koala::Facebook::OAuth.new.exchange_access_token_info(token) 
    update(access_token: new_token_info["access_token"], expires_at: Time.zone.now + new_token_info["expires_in"]) 
end 

Możesz sprawdzić gorails screencast, który wyjaśnia to na głębokości.