Skip to content

Commit

Permalink
Merge pull request #396 from krvss/master
Browse files Browse the repository at this point in the history
Facebook Canvas application authentication
  • Loading branch information
omab committed Jul 12, 2012
2 parents 77087cf + 2171b04 commit 186188b
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 5 deletions.
11 changes: 9 additions & 2 deletions README.rst
Expand Up @@ -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
^^^^^
Expand Down
11 changes: 9 additions & 2 deletions doc/backends/facebook.rst
Expand Up @@ -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/
Expand Down
78 changes: 78 additions & 0 deletions example/app/facebook.py
@@ -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))
7 changes: 7 additions & 0 deletions example/settings.py
Expand Up @@ -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
Expand Down
60 changes: 60 additions & 0 deletions example/templates/facebook.html
@@ -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 %}
1 change: 1 addition & 0 deletions example/templates/home.html
Expand Up @@ -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>
Expand Down
3 changes: 2 additions & 1 deletion example/urls.py
Expand Up @@ -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()

Expand All @@ -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 186188b

Please sign in to comment.