Permalink
Browse files

Facebook canvas application auth example

  • Loading branch information...
1 parent 77087cf commit 2171b04dabe6064cf4fda8003fd56ec880b9ec85 @krvss krvss committed Jul 12, 2012
Showing with 166 additions and 5 deletions.
  1. +9 −2 README.rst
  2. +9 −2 doc/backends/facebook.rst
  3. +78 −0 example/app/facebook.py
  4. +7 −0 example/settings.py
  5. +60 −0 example/templates/facebook.html
  6. +1 −0 example/templates/home.html
  7. +2 −1 example/urls.py
View
@@ -823,8 +823,15 @@ http://127.0.0.1:8000 or http://localhost:8000 because it won't work when
testing. Instead I define http://myapp.com and setup a mapping on /etc/hosts
or use dnsmasq_.
-If you need to perform authentication from Facebook Canvas application, take a
-look to `Facebook Canvas Application Authentication`_.
+If you need to perform authentication from Facebook Canvas application:
+ - Create your canvas application at http://developers.facebook.com/apps
+ - In Facebook application settings specify your canvas URL ``mysite.com/fb`` (current default)
+ - Setup your Django Social Auth settings like you usually do for Facebook authentication (FACEBOOK_APP_ID etc)
+ - Launch manage.py via sudo ``./manage.py mysite.com:80`` for browser to be able to load it when Facebook calls canvas URL
+ - Open your Facebook page via http://apps.facebook.com/app_namespace or better via http://www.facebook.com/pages/user-name/user-id?sk=app_app-id
+ - After that you will see this page in a right way and will able to connect to application and login automatically after connection
+
+More info on the topic at `Facebook Canvas Application Authentication`_.
Orkut
^^^^^
View
@@ -32,8 +32,15 @@ http://127.0.0.1:8000 or http://localhost:8000 because it won't work when
testing. Instead I define http://myapp.com and setup a mapping on /etc/hosts
or use dnsmasq_.
-If you need to perform authentication from Facebook Canvas application, take a
-look to `Facebook Canvas Application Authentication`_.
+If you need to perform authentication from Facebook Canvas application:
+ - Create your canvas application at http://developers.facebook.com/apps
+ - In Facebook application settings specify your canvas URL ``mysite.com/fb`` (current default)
+ - Setup your Django Social Auth settings like you usually do for Facebook authentication (FACEBOOK_APP_ID etc)
+ - Launch manage.py via sudo ``./manage.py mysite.com:80`` for browser to be able to load it when Facebook calls canvas URL
+ - Open your Facebook page via http://apps.facebook.com/app_namespace or better via http://www.facebook.com/pages/user-name/user-id?sk=app_app-id
+ - After that you will see this page in a right way and will able to connect to application and login automatically after connection
+
+More info on the topic at `Facebook Canvas Application Authentication`_.
.. _dnsmasq: http://www.thekelleys.org.uk/dnsmasq/doc.html
.. _Facebook development resources: http://developers.facebook.com/docs/authentication/
View
@@ -0,0 +1,78 @@
+from django.contrib.auth import BACKEND_SESSION_KEY
+from django.contrib.auth.models import AnonymousUser
+from django.http import HttpResponse
+from django.shortcuts import render_to_response
+from django.template.context import RequestContext
+
+from django.views.decorators.csrf import csrf_exempt
+from django.core.cache import cache
+
+from social_auth.models import UserSocialAuth
+from social_auth.views import complete as social_complete
+from social_auth.utils import setting
+from social_auth.backends.facebook import load_signed_request, FacebookBackend
+
+def is_complete_authentication(request):
+ return request.user.is_authenticated() and FacebookBackend.__name__ in request.session.get(BACKEND_SESSION_KEY, '')
+
+def get_access_token(user):
+ key = str(user.id)
+ access_token = cache.get(key)
+
+ # If cache is empty read the database
+ if access_token is None:
+ try:
+ social_user = user.social_user if hasattr(user, 'social_user') \
+ else UserSocialAuth.objects.get(user=user.id, provider=FacebookBackend.name)
+ except UserSocialAuth.DoesNotExist:
+ return None
+
+ if social_user.extra_data:
+ access_token = social_user.extra_data.get('access_token')
+ expires = social_user.extra_data.get('expires')
+
+ cache.set(key, access_token, int(expires) if expires is not None else 0)
+
+ return access_token
+
+# Facebook decorator to setup environment
+def facebook_decorator(func):
+ def wrapper(request, *args, **kwargs):
+ user = request.user
+
+ # User must me logged via FB backend in order to ensure we talk about the same person
+ if not is_complete_authentication(request):
+ try:
+ user = social_complete(request, FacebookBackend.name)
+ except ValueError:
+ pass # no matter if failed
+
+ # Not recommended way for FB, but still something we need to be aware of
+ if isinstance(user, HttpResponse):
+ kwargs.update({'auth_response': user})
+ # Need to re-check the completion
+ else:
+ if is_complete_authentication(request):
+ kwargs.update({'access_token': get_access_token(request.user)})
+ else:
+ request.user = AnonymousUser()
+
+ signed_request = load_signed_request(request.REQUEST.get('signed_request', ''))
+ if signed_request:
+ kwargs.update({'signed_request': signed_request})
+
+ return func(request, *args, **kwargs)
+
+ return wrapper
+
+
+@csrf_exempt
+@facebook_decorator
+def facebook_view(request, *args, **kwargs):
+ # If there is a ready response just return it. Not recommended though.
+ auth_response = kwargs.get('auth_response')
+ if auth_response:
+ return auth_response
+
+ return render_to_response('facebook.html', {'fb_app_id':setting('FACEBOOK_APP_ID'),
+ 'warning': request.method == 'GET'}, RequestContext(request))
View
@@ -24,6 +24,13 @@
}
}
+CACHES = {
+ 'default': {
+ 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+ 'LOCATION': 'unique-snowflake'
+ }
+}
+
TIME_ZONE = 'America/Chicago'
LANGUAGE_CODE = 'en-us'
SITE_ID = 1
@@ -0,0 +1,60 @@
+{% extends "base.html" %}
+
+{% block script %}
+ <script type="text/javascript">
+ function startConnect(){
+ FB.login(function(response) {
+ if (response.authResponse) {
+ window.location = window.location +
+ '?access_token=' + response.authResponse.accessToken +
+ '&expires=' + response.authResponse.expiresIn +
+ '&signed_request=' + response.authResponse.signedRequest;
+ }
+
+ }, {scope: "{{ app_scope }}" })
+ }
+ </script>
+{% endblock %}
+
+{% block heading %}Facebook Canvas Application Authentication{% endblock %}
+{% block content %}
+ {% if user.is_anonymous %}
+ {% if warning %}
+ <p>You are using GET request to this page, and this is not something Facebook usually does.
+ To make a real test you need to do following:
+ </p>
+ <ol>
+ <li>Create your canvas application at <a href="https://developers.facebook.com/apps">Facebook</a>.</li>
+ <li>In Facebook application settings specify your canvas URL <b>mysite.com</b>/fb (current default). </li>
+ <li>Setup your Django Social Auth settings like you usually do for Facebook authentication (FACEBOOK_APP_ID etc).</li>
+ <li>Launch manage.py via sudo ./manage.py <b>mysite.com</b>:80 for browser to be able to load it when Facebook calls canvas URL.</li>
+ <li>Open your Facebook page via apps.facebook.com/<b>app_namespace</b> or better via www.facebook.com/pages/<b>user-name</b>/<b>user-id</b>?sk=app_<b>app-id</b></li>
+ <li>After that you will see this page in a right way and will able to connect to application and login automatically after connection.</li>
+ </ol>
+ {% else %}
+ <p>You are a guest in this Facebook application.</p>
+ <a href="#" onclick="startConnect(); return false;">Click to connect and authenticate</a>
+ {% endif %}
+ {% else %}
+ <p>Authenticated successfully as {{ user }}</p>
+ <a href="{% url done %}">Done</a>
+ {% endif %}
+
+ <div id="fb-root"></div>
+ <script type="text/javascript">
+ window.fbAsyncInit = function() {
+ FB.init({appId: {{ fb_app_id }}, status: true, cookie: true, xfbml: true, oauth: true});
+
+ window.setTimeout(function() {
+ FB.Canvas.setAutoResize();
+ }, 250);
+};
+
+ (function() {
+ var e = document.createElement('script'); e.async = true;
+ e.src = document.location.protocol +
+ '//connect.facebook.net/ru_RU/all.js';
+ document.getElementById('fb-root').appendChild(e);
+ }());
+ </script>
+{% endblock %}
@@ -91,6 +91,7 @@ <h3>Login using <a href="https://browserid.org/" title="BrowserID">BrowserID</a>
<div>
<h3>Login using other authentication systems:</h3>
<ul>
+ <li><a rel="nofollow" href="{% url fb_app %}">Facebook Canvas Application</a></li>
<li><a rel="nofollow" href="{% url socialauth_begin "vkontakte" %}">VKontakte OpenAPI</a></li>
</ul>
</div>
View
@@ -2,7 +2,7 @@
from django.contrib import admin
from app.views import home, done, logout, error, form, form2
-
+from app.facebook import facebook_view
admin.autodiscover()
@@ -14,5 +14,6 @@
url(r'^form/$', form, name='form'),
url(r'^form2/$', form2, name='form2'),
url(r'^admin/', include(admin.site.urls)),
+ url(r'^fb/', facebook_view, name='fb_app'),
url(r'', include('social_auth.urls')),
)

0 comments on commit 2171b04

Please sign in to comment.