Rejestracja wspierana Facebookiem w Django

Wykorzystujemy widżet Facebook registration tool do rejestracji użytkownika z wykorzystaniem jego konta na Facebooku

Facebook niedawno wprowadził kolejny społecznościowy widget - formularz rejestracji wspierany danymi z Facebooka (Facebook registration tool). Jeżeli wchodzący na twoją stronę użytkownik ma konto na Facebooku i jest tam zalogowany to w formularzu rejestracji zobaczy swoje dane i wystarczy że kliknie "Zarejestruj się":
fbreg
Nowy widżet posiada wiele dodatkowych opcji jak możliwość dodania własnych pól i wybrania danych z profilu użytkownika FB jakie będą nam potrzebne. Wszystko opisano w dokumentacji. W tym artykule zaprezentuję prosty przykład implementacji tego widżetu w Django do szybkiej rejestracji użytkowników. W porównaniu do istniejących rozwiązań umożliwiających szybką rejestrację jak przycisk logowania Facebooka (dawniej FB Connect, teraz FB Graph), czy usług typu RPXnow to rozwiązanie pozwala na przeprowadzenie pełnej rejestracji w jednym etapie - użytkownik widzi formularz rejestracji, w którym mogą być nasze dodatkowe pola. Przy wcześniejszych rozwiązaniach najpierw trzeba było skorzystać z przycisku i po automatycznej rejestracji poprosić o dodatkowe dane. Jeżeli twoja aplikacja nie wymaga dodatkowych danych od użytkowników przy rejestracji to registration tool nie będzie ci potrzebne.

Przygotowania - aplikacja na Facebooku

  • Na początek musimy stworzyć aplikację na Facebooku potrzebną do obsługi widżeta. W jej ustawieniach pod zakładką "Strona Aplikacji" musimy podać domenę, na której będziemy jej używać (domena naszego serwisu).
  • Mając aplikację zapisujemy jej identyfikator oraz "App Secret" - możemy dodać to od razu do settingsów projektu Django.

Wstawiamy widżet na stronę

Widżet Facebook registration tool możemy wstawić poprzez ramkę lub XFBML. W przypadku ramki wystarczy wkleić coś takiego:
<iframe src="http://www.facebook.com/plugins/registration.php?
             client_id=ID_APLIKACJI_FB&
             redirect_uri=http://www.twojadomena.com/url/odbiorczy/&
             fields=name,birthday,gender,location,email"
        scrolling="auto"
        frameborder="no"
        style="border:none"
        allowTransparency="true"
        width="100%"
        height="310px">
</iframe>
Gdzie ID_APLIKACJI_FB to numer/identyfikator aplikacji na Facebooku. Musimy podać też wartośc redirect_uri - adres URL widoku na naszej stronie obsługującego odbiór danych. Po otwarciu strony z poprawnie skonfigurowaną ramką powinniśmy zobaczyć zaprezentowany wcześniej widget. Teraz trzeba obsłużyć dane zwrócone przez Facebooka po wysłaniu formularza przez użytkownika.

Odbiór danych rejestracji

Facebook na podany adres URL odeśle wszystkie dane (jeżeli użytkownik zezwoli na to naszej aplikacji i będzie chciał się zarejestrować). W POST dostaniemy dane pod zmienną signed_request składającą się z podpisu i danych zakodowany w base64. Musimy rozbić łańcuch na podpis i dane (po kropce), rozkodować za pomocą base64 dane (w formacie JSON) a następnie sprawdzić czy podpis jest poprawny (generowany z wysłanych danych oraz "App Secret" naszej aplikacji). Po potwierdzeniu poprawności podpisu można wykorzystać dane takie jak email, login, czy ID użytkownika Facebooka, który się chce zarejestrować. Oto przykład widoku oraz funkcji obsługujące podpisane żądania Facebooka:
from random import choice
import hashlib
import urllib2
import json
import base64
import hmac

def parse_signed_request(signed_request, app_secret):
    """Return dictionary with signed request data.
    Code taken from https://github.com/facebook/python-sdk"""
    try:
      l = signed_request.split('.', 2)
      encoded_sig = str(l[0])
      payload = str(l[1])
    except IndexError:
      raise ValueError("'signed_request' malformed")
    
    sig = base64.urlsafe_b64decode(encoded_sig + "=" * ((4 - len(encoded_sig) % 4) % 4))
    data = base64.urlsafe_b64decode(payload + "=" * ((4 - len(payload) % 4) % 4))

    data = json.loads(data)

    if data.get('algorithm').upper() != 'HMAC-SHA256':
      raise ValueError("'signed_request' is using an unknown algorithm")
    else:
      expected_sig = hmac.new(app_secret, msg=payload, digestmod=hashlib.sha256).digest()

    if sig != expected_sig:
      raise ValueError("'signed_request' signature mismatch")
    else:
      return data

def fb_registration(request):
	"""
	Register a user from Facebook-aided registration form
	"""
	if request.POST:
		if 'signed_request' in request.POST:
			# parse and check data
			data = parse_signed_request(request.POST['signed_request'], settings.FACEBOOK_CONNECT_SECRET)
			
			# lets try to check if user exists based on username or email
			try:
				check_user = User.objects.get(username=data['registration']['name'])
			except:
				pass
			else:
				return HttpResponseRedirect('/user/login/')
			
			try:
				check_user = User.objects.get(email=data['registration']['email'])
			except:
				pass
			else:
				return HttpResponseRedirect('/user/login/')
			
			# user does not exist. We create an account
			# in this example I assume that he will login via Facebook button or RPXnow
			# so no password is needed for him - using random password to make Django happy
			randompass = ''.join([choice('1234567890qwertyuiopasdfghjklzxcvbnm') for i in range(7)])
			user = User.objects.create_user(data['registration']['name'], data['registration']['email'], randompass)
			user.save()
			user = authenticate(username=data['registration']['name'], password=randompass)
			if user is not None:
				# save in user profile his facebook id. In this case for RPXNow login widget
				fbid = 'http://www.facebook.com/profile.php?id=%s' % data['user_id']
				r = RPXAssociation(user=user, identifier=fbid)
				r.save()
				login(request, user)
			return HttpResponseRedirect('/')
			
	return render_to_response('userpanel/fb_registration.html', {}, context_instance=RequestContext(request, userpanelContext(request)))
W powyższym przykładzie mamy widok, który odbiera dane z rejestracji i tworzy nowe konto jeżeli dane są poprawne a użytkownik nie jest już zarejestrowany (wtedy przenosi do logowania).
blog comments powered by Disqus

Kategorie

Strony