From 0614f67b40ad2263bef0303193b79b2d3f414c71 Mon Sep 17 00:00:00 2001 From: Stas Kravets Date: Wed, 19 Jan 2011 12:04:12 +0300 Subject: [PATCH] VKontakte support - initial version. --- example/app/views.py | 2 + example/local_settings.py.template | 3 ++ example/settings.py | 1 + example/templates/home.html | 7 +++ example/templates/vk.html | 38 ++++++++++++++++ social_auth/vk.py | 71 ++++++++++++++++++++++++++++++ 6 files changed, 122 insertions(+) create mode 100644 example/templates/vk.html create mode 100644 social_auth/vk.py diff --git a/example/app/views.py b/example/app/views.py index 50f3b3e..941c915 100644 --- a/example/app/views.py +++ b/example/app/views.py @@ -4,6 +4,8 @@ from django.contrib.auth.decorators import login_required from django.template import RequestContext from django.shortcuts import render_to_response +from social_auth.vk import add_VK_Auth +add_VK_Auth() def home(request): """Home view, displays login mechanism""" diff --git a/example/local_settings.py.template b/example/local_settings.py.template index e43eba8..300a597 100644 --- a/example/local_settings.py.template +++ b/example/local_settings.py.template @@ -9,4 +9,7 @@ SOCIAL_AUTH_FORCE_RANDOM_USERNAME = False SOCIAL_AUTH_DEFAULT_USERNAME = 'socialauth_user' SOCIAL_AUTH_COMPLETE_URL_NAME = 'social:complete' LOGIN_ERROR_URL = '/login/error/' +VKONTAKTE_APP_ID = '' +VKONTAKTE_APP_SECRET = '' +VKONTAKTE_LOCAL_HTML = '' #SOCIAL_AUTH_USER_MODEL = 'app.CustomUser' diff --git a/example/settings.py b/example/settings.py index 8ea7770..59fe422 100644 --- a/example/settings.py +++ b/example/settings.py @@ -69,6 +69,7 @@ AUTHENTICATION_BACKENDS = ( 'social_auth.backends.YahooBackend', 'social_auth.backends.OpenIDBackend', 'social_auth.backends.LiveJournalBackend', + 'social_auth.vk.VKontakteBackend', 'django.contrib.auth.backends.ModelBackend', ) diff --git a/example/templates/home.html b/example/templates/home.html index f54d252..74d20cc 100644 --- a/example/templates/home.html +++ b/example/templates/home.html @@ -39,4 +39,11 @@ + +
+

Login using other authentication systems:

+ +
{% endblock %} diff --git a/example/templates/vk.html b/example/templates/vk.html new file mode 100644 index 0000000..137a105 --- /dev/null +++ b/example/templates/vk.html @@ -0,0 +1,38 @@ +{% extends "base.html" %} + +{% block heading %}VKontakte login{% endblock %} + +{% block content %} + + + + + +
Logging in, please wait...
+{% endblock %} diff --git a/social_auth/vk.py b/social_auth/vk.py new file mode 100644 index 0000000..f465e5f --- /dev/null +++ b/social_auth/vk.py @@ -0,0 +1,71 @@ +from django.conf import settings +from django.contrib.auth import authenticate +from urllib import unquote +import md5 + +from backends import SocialAuthBackend, USERNAME +from auth import BaseAuth, BACKENDS + + +class VKontakteBackend(SocialAuthBackend): + """VKontakte authentication backend""" + name = 'vkontakte' + + def get_user_id(self, details, response): + """Return user unique id provided by VKontakte""" + return int(response.GET['id']) + + def get_user_details(self, response): + """Return user details from VKontakte request""" + values = { USERNAME: unquote(response.GET['nickname']), 'email': '', 'fullname': '', + 'first_name': unquote(response.GET['first_name']), 'last_name': unquote(response.GET['last_name'])} + return values + + +class VKontakteAuth(BaseAuth): + """VKontakte OpenAPI authorization mechanism""" + AUTH_BACKEND = VKontakteBackend + APP_ID = settings.VKONTAKTE_APP_ID + + def auth_html(self): + """Returns local VK authentication page, not necessary for VK to authenticate """ + from django.core.urlresolvers import reverse + from django.template import RequestContext, loader + + dict = { 'VK_APP_ID' : self.APP_ID, + 'VK_COMPLETE_URL': reverse('social:complete', args=[VKontakteBackend.name]) } + + vk_template = loader.get_template(settings.VKONTAKTE_LOCAL_HTML) + context = RequestContext(self.request, dict) + + return vk_template.render(context) + + def auth_complete(self, *args, **kwargs): + """Performs check of authentication in VKontakte, returns User if succeeded""" + app_cookie = 'vk_app_' + self.APP_ID + + if not 'id' in self.request.GET or not app_cookie in self.request.COOKIES: + raise ValueError('VKontakte authentication is not completed') + + cookie_dict = dict(item.split('=') for item in self.request.COOKIES[app_cookie].split('&')) + check_str = ''.join([item + '=' + cookie_dict[item] for item in ['expire', 'mid', 'secret', 'sid']]) + + hash = md5.new(check_str + settings.VKONTAKTE_APP_SECRET).hexdigest() + + if hash != cookie_dict['sig']: + raise ValueError('VKontakte authentication failed: invalid hash') + else: + kwargs.update({'response': self.request, self.AUTH_BACKEND.name: True}) + return authenticate(*args, **kwargs) + + @property + def uses_redirect(self): + """VKontakte does not require visiting server url in order + to do authentication, so auth_xxx methods are not needed to be called. + Their current implementation is just an example""" + return False + + +def add_VK_Auth(): + BACKENDS[VKontakteBackend.name] = VKontakteAuth + -- 2.39.5