canvas app work, need to write tests for it
This commit is contained in:
parent
0937d2ba9d
commit
6a3f2f73d5
39
README
39
README
@ -36,7 +36,7 @@ shared login partial.
|
||||
<%= fb_connect_async_js %>
|
||||
<% if current_facebook_user %>
|
||||
<%= "Welcome #{current_facebook_user.first_name} #{current_facebook_user.last_name}!" %>
|
||||
or
|
||||
or
|
||||
<%= "Hello #{fb_name(current_facebook_user, :useyou => false)}!" # link to facebook profile
|
||||
%>
|
||||
<%= fb_logout_link("Logout of fb", request.url) %><br />
|
||||
@ -48,4 +48,41 @@ shared login partial.
|
||||
<%= fb_login_and_redirect('<your URL here>', :perms => 'email,user_birthday') %>
|
||||
<% end %>
|
||||
|
||||
Using with Canvas Applications
|
||||
==============================
|
||||
|
||||
To improve integration with Facebook and iframe canvas applications, the primary goal
|
||||
being things like FB.ui work as a dialog rather than a popup, the application
|
||||
needs to be authenticated against the user's account via OAuth before use.
|
||||
|
||||
0. Prerequisite: You need a Facebook app. Have your canvas page name handy.
|
||||
|
||||
1. Install facebooker2.
|
||||
|
||||
2. Create config/facebooker.yml as above, but add the following key:
|
||||
|
||||
production:
|
||||
canvas_page_name: <your canvas page name>
|
||||
|
||||
3. Add the following lines to your app/controllers/application_controller.rb
|
||||
|
||||
include Facebooker2::Rails::Controller::CanvasOAuth
|
||||
|
||||
ensure_canvas_connected_to_facebook :oauth_url, 'publish_stream'
|
||||
create_facebook_oauth_callback :oauth
|
||||
|
||||
rescue_from Facebooker2::OAuthException do |exception|
|
||||
redirect_to 'http://www.facebook.com/'
|
||||
end
|
||||
|
||||
4. Create a route that generates a URL for the OAuth callback and calls the appropriate
|
||||
action on your controller:
|
||||
|
||||
map.oauth '/oauth', :controller => :application, :action => :oauth
|
||||
|
||||
5. Your canvas application will now ensure that the current user has authorized
|
||||
the application before anything else is allowed. The authorization and FB.ui dialogs
|
||||
will appear inline instead of as popups, improving user experience.
|
||||
|
||||
Copyright (c) 2010 Mike Mangino, released under the MIT license
|
||||
Copyright (c) 2010 John Bintz, released under the MIT license
|
||||
|
@ -1,35 +1,37 @@
|
||||
# Facebooker2
|
||||
require "mogli"
|
||||
|
||||
module Facebooker2
|
||||
class NotConfigured < Exception; end
|
||||
class << self
|
||||
attr_accessor :api_key, :secret, :app_id
|
||||
attr_accessor :api_key, :secret, :app_id, :canvas_page_name
|
||||
end
|
||||
|
||||
|
||||
def self.secret
|
||||
@secret || raise_unconfigured_exception
|
||||
@secret || raise_unconfigured_exception
|
||||
end
|
||||
|
||||
|
||||
def self.app_id
|
||||
@app_id || raise_unconfigured_exception
|
||||
end
|
||||
|
||||
|
||||
def self.raise_unconfigured_exception
|
||||
raise NotConfigured.new("No configuration provided for Facebooker2. Either set the app_id and secret or call Facebooker2.load_facebooker_yaml in an initializer")
|
||||
end
|
||||
|
||||
|
||||
def self.configuration=(hash)
|
||||
self.api_key = hash[:api_key]
|
||||
self.secret = hash[:secret]
|
||||
self.app_id = hash[:app_id]
|
||||
self.canvas_page_name = hash[:canvas_page_name]
|
||||
end
|
||||
|
||||
|
||||
def self.load_facebooker_yaml
|
||||
config = YAML.load(File.read(File.join(::Rails.root,"config","facebooker.yml")))[::Rails.env]
|
||||
raise NotConfigured.new("Unable to load configuration for #{::Rails.env} from facebooker.yml. Is it set up?") if config.nil?
|
||||
self.configuration = config.with_indifferent_access
|
||||
end
|
||||
|
||||
|
||||
def self.cast_to_facebook_id(object)
|
||||
if object.kind_of?(Mogli::Profile)
|
||||
object.id
|
||||
@ -43,8 +45,10 @@ end
|
||||
|
||||
|
||||
require "facebooker2/rails/controller"
|
||||
require "facebooker2/rails/controller/canvas_oauth"
|
||||
require "facebooker2/rails/helpers/facebook_connect"
|
||||
require "facebooker2/rails/helpers/javascript"
|
||||
require "facebooker2/rails/helpers/request_forms"
|
||||
require "facebooker2/rails/helpers/user"
|
||||
require "facebooker2/rails/helpers"
|
||||
require "facebooker2/rails/helpers"
|
||||
require "facebooker2/oauth_exception"
|
||||
|
4
lib/facebooker2/oauth_exception.rb
Normal file
4
lib/facebooker2/oauth_exception.rb
Normal file
@ -0,0 +1,4 @@
|
||||
module Facebooker2
|
||||
class OAuthException < StandardError; end
|
||||
end
|
||||
|
@ -3,31 +3,31 @@ require "hmac-sha2"
|
||||
module Facebooker2
|
||||
module Rails
|
||||
module Controller
|
||||
|
||||
|
||||
def self.included(controller)
|
||||
controller.helper Facebooker2::Rails::Helpers
|
||||
controller.helper_method :current_facebook_user
|
||||
controller.helper_method :current_facebook_client
|
||||
controller.helper_method :facebook_params
|
||||
end
|
||||
|
||||
|
||||
def current_facebook_user
|
||||
fetch_client_and_user
|
||||
@_current_facebook_user
|
||||
end
|
||||
|
||||
|
||||
def current_facebook_client
|
||||
fetch_client_and_user
|
||||
@_current_facebook_client
|
||||
end
|
||||
|
||||
|
||||
def fetch_client_and_user
|
||||
return if @_fb_user_fetched
|
||||
fetch_client_and_user_from_cookie
|
||||
fetch_client_and_user_from_signed_request unless @_current_facebook_client
|
||||
@_fb_user_fetched = true
|
||||
end
|
||||
|
||||
|
||||
def fetch_client_and_user_from_cookie
|
||||
app_id = Facebooker2.app_id
|
||||
if (hash_data = fb_cookie_hash_for_app_id(app_id)) and
|
||||
@ -35,20 +35,20 @@ module Facebooker2
|
||||
fb_create_user_and_client(hash_data["access_token"],hash_data["expires"],hash_data["uid"])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def fb_create_user_and_client(token,expires,userid)
|
||||
client = Mogli::Client.new(token,expires.to_i)
|
||||
user = Mogli::User.new(:id=>userid)
|
||||
fb_sign_in_user_and_client(user,client)
|
||||
fb_sign_in_user_and_client(user,client)
|
||||
end
|
||||
|
||||
|
||||
def fb_sign_in_user_and_client(user,client)
|
||||
user.client = client
|
||||
@_current_facebook_user = user
|
||||
@_current_facebook_client = client
|
||||
@_fb_user_fetched = true
|
||||
end
|
||||
|
||||
|
||||
def fb_cookie_hash_for_app_id(app_id)
|
||||
return nil unless fb_cookie_for_app_id?(app_id)
|
||||
hash={}
|
||||
@ -59,15 +59,15 @@ module Facebooker2
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
|
||||
def fb_cookie_for_app_id?(app_id)
|
||||
!fb_cookie_for_app_id(app_id).nil?
|
||||
end
|
||||
|
||||
|
||||
def fb_cookie_for_app_id(app_id)
|
||||
cookies["fbs_#{app_id}"]
|
||||
end
|
||||
|
||||
|
||||
def fb_cookie_signature_correct?(hash,secret)
|
||||
sorted_keys = hash.keys.reject {|k| k=="sig"}.sort
|
||||
test_string = ""
|
||||
@ -77,13 +77,13 @@ module Facebooker2
|
||||
test_string += secret
|
||||
Digest::MD5.hexdigest(test_string) == hash["sig"]
|
||||
end
|
||||
|
||||
|
||||
def fb_signed_request_json(encoded)
|
||||
chars_to_add = 4-(encoded.size % 4)
|
||||
encoded += ("=" * chars_to_add)
|
||||
Base64.decode64(encoded)
|
||||
end
|
||||
|
||||
|
||||
def facebook_params
|
||||
@facebook_param ||= fb_load_facebook_params
|
||||
end
|
||||
@ -93,20 +93,21 @@ module Facebooker2
|
||||
sig,encoded_json = params[:signed_request].split(".")
|
||||
return {} unless fb_signed_request_sig_valid?(sig,encoded_json)
|
||||
ActiveSupport::JSON.decode(fb_signed_request_json(encoded_json)).with_indifferent_access
|
||||
end
|
||||
|
||||
def fb_signed_request_sig_valid?(sig,encoded)
|
||||
end
|
||||
|
||||
def fb_signed_request_sig_valid?(sig,encoded)
|
||||
base64 = Base64.encode64(HMAC::SHA256.digest(Facebooker2.secret,encoded))
|
||||
#now make the url changes that facebook makes
|
||||
url_escaped_base64 = base64.gsub(/=*\n?$/,"").tr("+/","-_")
|
||||
sig == url_escaped_base64
|
||||
end
|
||||
|
||||
|
||||
def fetch_client_and_user_from_signed_request
|
||||
if facebook_params[:oauth_token]
|
||||
fb_create_user_and_client(facebook_params[:oauth_token],facebook_params[:expires],facebook_params[:user_id])
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
55
lib/facebooker2/rails/controller/canvas_oauth.rb
Normal file
55
lib/facebooker2/rails/controller/canvas_oauth.rb
Normal file
@ -0,0 +1,55 @@
|
||||
module Facebooker2
|
||||
module Rails
|
||||
module Controller
|
||||
module CanvasOAuth
|
||||
def self.included(controller)
|
||||
controller.extend(CanvasOAuthClass)
|
||||
|
||||
class << controller
|
||||
attr_accessor :_facebooker_oauth_callback_url, :_facebooker_scope
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
def canvas_oauth_connect
|
||||
raise "Canvas page name not defined! Define it in config/facebooker.yml as #{::Rails.env}: canvas_page_name: <your url>." if !Facebooker2.canvas_page_name
|
||||
if params[:error]
|
||||
raise Facebooker2::OAuthException.new(params[:error][:message])
|
||||
else
|
||||
redirect_to ('http://apps.facebook.com/' + Facebooker2.canvas_page_name) if params[:code]
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
def ensure_canvas_connected
|
||||
case self.class._facebooker_oauth_callback_url
|
||||
when Symbol
|
||||
callback_url = send(self.class._facebooker_oauth_callback_url)
|
||||
end
|
||||
|
||||
if current_facebook_user == nil && !params[:code] && !params[:error]
|
||||
render :text => "<script>top.location.href = 'https://graph.facebook.com/oauth/authorize?client_id=#{Facebooker2.app_id}&redirect_uri=#{callback_url}&scope=#{[ self.class._facebooker_scope ].flatten * ','}'</script>"
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module CanvasOAuthClass
|
||||
def ensure_canvas_connected_to_facebook(oauth_callback_url, *scope)
|
||||
self._facebooker_oauth_callback_url = oauth_callback_url
|
||||
self._facebooker_scope = scope
|
||||
|
||||
before_filter :ensure_canvas_connected
|
||||
end
|
||||
|
||||
def create_facebook_oauth_callback(method_name)
|
||||
self.class_eval(<<-EOT)
|
||||
def #{method_name}
|
||||
return canvas_oauth_connect
|
||||
end
|
||||
EOT
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
0
spec/rails/controller/canvas_oauth_spec.rb
Normal file
0
spec/rails/controller/canvas_oauth_spec.rb
Normal file
Loading…
Reference in New Issue
Block a user