]> git.parisson.com Git - django-social-auth.git/commitdiff
VKontakte support - initial version.
authorStas Kravets <skravets@internal-rfc1918.hn.nnov.stream.ru>
Wed, 19 Jan 2011 09:04:12 +0000 (12:04 +0300)
committerStas Kravets <skravets@internal-rfc1918.hn.nnov.stream.ru>
Wed, 19 Jan 2011 09:04:12 +0000 (12:04 +0300)
example/app/views.py
example/local_settings.py.template
example/settings.py
example/templates/home.html
example/templates/vk.html [new file with mode: 0644]
social_auth/vk.py [new file with mode: 0644]

index 50f3b3ea9fb71641a4d0b1cffde95a5b7181b182..941c915b0fcdbaf08968b318ba27bf37050d9386 100644 (file)
@@ -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"""
index e43eba892d9a604a4488d5221778c3fd0f6eec60..300a597fc8b3347d7850376a497c378d376be324 100644 (file)
@@ -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'
index 8ea77709b8c663a90ab3243d35c3150e9709d16d..59fe4229d7f14f2817bff59d57c9cbe404c63d12 100644 (file)
@@ -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',
 )
 
index f54d252e07657b9078607930f5a5da0669ccbb9c..74d20cc8668af1315bdd78d0b0fdcc6e34d5885f 100644 (file)
     </li>
   </ul>
 </div>
+
+<div>
+  <h3>Login using other authentication systems:</h3>
+       <ul>
+               <li><a rel="nofollow" href="/login/vkontakte/">VKontakte OpenAPI</a></li>
+       </ul>
+</div>
 {% endblock %}
diff --git a/example/templates/vk.html b/example/templates/vk.html
new file mode 100644 (file)
index 0000000..137a105
--- /dev/null
@@ -0,0 +1,38 @@
+{% extends "base.html" %}
+
+{% block heading %}<a href="http://www.vkontakte.ru">VKontakte</a> login{% endblock %}
+
+{% block content %}
+
+<script src="http://vkontakte.ru/js/api/openapi.js" type="text/javascript"></script>
+
+<script type="text/javascript">
+       var vkAppId = {{ VK_APP_ID|default:"null" }};
+
+       if (vkAppId)
+               VK.init({ apiId: vkAppId });
+
+       function authVK() {
+               if (!vkAppId) {
+                       alert ("Please specify VKontakte APP ID in your local settings file");
+                       return false;
+               }
+               
+               VK.Auth.login(function(response) {
+                       var params = "";
+                       if (response.session) {
+                               params = "first_name=" + encodeURI(response.session.user.first_name) + "&last_name=" + encodeURI(response.session.user.last_name);
+                               params += "&nickname=" + encodeURI(response.session.user.nickname) + "&id=" + encodeURI(response.session.user.id);
+                       }
+                       window.location = "{{ VK_COMPLETE_URL }}?" + params;
+
+               });
+               return false;
+       }
+       
+       window.onload = authVK();
+       
+</script>
+
+<div id="status">Logging in, please wait...</div>
+{% endblock %}
diff --git a/social_auth/vk.py b/social_auth/vk.py
new file mode 100644 (file)
index 0000000..f465e5f
--- /dev/null
@@ -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
+