From d5a62c84ea0878e3fc309f8a6e999f5992a2b815 Mon Sep 17 00:00:00 2001 From: duoduo369 Date: Sun, 17 May 2015 15:40:01 +0800 Subject: [PATCH] add weixin backends Weixin is Tencent's icq, in China there are million's people use it. --- social/backends/weixin.py | 99 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 social/backends/weixin.py diff --git a/social/backends/weixin.py b/social/backends/weixin.py new file mode 100644 index 000000000..5170cafd2 --- /dev/null +++ b/social/backends/weixin.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +# author:duoduo3369@gmail.com https://github.com/duoduo369 +""" +Weixin OAuth2 backend +""" +from requests import HTTPError + +from social.backends.oauth import BaseOAuth2 +from social.exceptions import AuthCanceled, AuthUnknownError + + +class WeixinOAuth2(BaseOAuth2): + """Weixin OAuth authentication backend""" + name = 'weixin' + ID_KEY = 'openid' + AUTHORIZATION_URL = 'https://open.weixin.qq.com/connect/qrconnect' + ACCESS_TOKEN_URL = 'https://api.weixin.qq.com/sns/oauth2/access_token' + ACCESS_TOKEN_METHOD = 'POST' + REDIRECT_STATE = False + EXTRA_DATA = [ + ('nickname', 'username'), + ('headimgurl', 'profile_image_url'), + ] + + def get_user_details(self, response): + """Return user details from Weixin. API URL is: + https://api.weixin.qq.com/sns/userinfo + """ + if self.setting('DOMAIN_AS_USERNAME'): + username = response.get('domain', '') + else: + username = response.get('nickname', '') + profile_image_url = response.get('headimgurl', '') + return {'username': username, 'profile_image_url': profile_image_url} + + def user_data(self, access_token, *args, **kwargs): + data = self.get_json('https://api.weixin.qq.com/sns/userinfo', + params={'access_token': access_token, + 'openid': kwargs['response']['openid']}) + nickname = data.get('nickname') + if nickname: + # weixin api has some encode bug, here need handle + data['nickname'] = nickname.encode('raw_unicode_escape').decode('utf-8') + return data + + + def auth_params(self, state=None): + appid, secret = self.get_key_and_secret() + params = { + 'appid': appid, + 'redirect_uri': self.get_redirect_uri(state) + } + if self.STATE_PARAMETER and state: + params['state'] = state + if self.RESPONSE_TYPE: + params['response_type'] = self.RESPONSE_TYPE + return params + + def auth_complete_params(self, state=None): + appid, secret = self.get_key_and_secret() + return { + 'grant_type': 'authorization_code', # request auth code + 'code': self.data.get('code', ''), # server response code + 'appid': appid, + 'secret': secret, + 'redirect_uri': self.get_redirect_uri(state) + } + + def refresh_token_params(self, token, *args, **kwargs): + appid, secret = self.get_key_and_secret() + return { + 'refresh_token': token, + 'grant_type': 'refresh_token', + 'appid': appid, + 'secret': secret + } + + def auth_complete(self, *args, **kwargs): + """Completes loging process, must return user instance""" + self.process_error(self.data) + try: + response = self.request_access_token( + self.ACCESS_TOKEN_URL, + data=self.auth_complete_params(self.validate_state()), + headers=self.auth_headers(), + method=self.ACCESS_TOKEN_METHOD + ) + except HTTPError as err: + if err.response.status_code == 400: + raise AuthCanceled(self) + else: + raise + except KeyError: + raise AuthUnknownError(self) + if 'errcode' in response: + raise AuthCanceled(self) + self.process_error(response) + return self.do_auth(response['access_token'], response=response, + *args, **kwargs)