-
Notifications
You must be signed in to change notification settings - Fork 759
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #396 from krvss/master
Facebook Canvas application authentication
- Loading branch information
Showing
7 changed files
with
166 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters