diff --git a/README.md b/README.md
index 2a4ea84..babd74a 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
- 支持文章全文搜索。
- 完整的评论功能,包括发表回复评论,以及评论的邮件提醒,支持`Markdown`。
- 侧边栏功能,最新文章,最多阅读,标签云等。
-- 支持Oauth登陆,现已有Google,GitHub,facebook,微博登录。
+- 支持Oauth登陆,现已有Google,GitHub,facebook,微博,QQ登录。
- 支持`Memcache`缓存,支持缓存自动刷新。
- 简单的SEO功能,新建文章等会自动通知Google和百度。
- 集成了简单的图床功能。
diff --git a/oauth/models.py b/oauth/models.py
index 9527d78..63b3c06 100644
--- a/oauth/models.py
+++ b/oauth/models.py
@@ -35,6 +35,7 @@ class OAuthConfig(models.Model):
('google', '谷歌'),
('github', 'GitHub'),
('facebook', 'FaceBook'),
+ ('qq', 'QQ'),
)
type = models.CharField('类型', max_length=10, choices=TYPE, default='a')
appkey = models.CharField(max_length=200, verbose_name='AppKey')
diff --git a/oauth/oauthmanager.py b/oauth/oauthmanager.py
index 22b2784..b3a4791 100644
--- a/oauth/oauthmanager.py
+++ b/oauth/oauthmanager.py
@@ -61,10 +61,12 @@ class BaseOauthManager(metaclass=ABCMeta):
def do_get(self, url, params):
rsp = requests.get(url=url, params=params)
+ logger.info(rsp.text)
return rsp.text
def do_post(self, url, params):
rsp = requests.post(url, params)
+ logger.info(rsp.text)
return rsp.text
def get_config(self):
@@ -272,7 +274,7 @@ class GitHubOauthManager(BaseOauthManager):
user.type = 'github'
user.token = self.access_token
user.matedata = rsp
- if datas['email']:
+ if 'email' in datas and datas['email']:
user.email = datas['email']
return user
@@ -339,9 +341,9 @@ class FaceBookOauthManager(BaseOauthManager):
user.type = 'facebook'
user.token = self.access_token
user.matedata = rsp
- if datas['email']:
+ if 'email' in datas and datas['email']:
user.email = datas['email']
- if datas['picture'] and datas['picture']['data'] and datas['picture']['data']['url']:
+ if 'picture' in datas and datas['picture'] and datas['picture']['data'] and datas['picture']['data']['url']:
user.picture = str(datas['picture']['data']['url'])
return user
except Exception as e:
@@ -349,6 +351,81 @@ class FaceBookOauthManager(BaseOauthManager):
return None
+class QQOauthManager(BaseOauthManager):
+ AUTH_URL = 'https://graph.qq.com/oauth2.0/authorize'
+ TOKEN_URL = 'https://graph.qq.com/oauth2.0/token'
+ API_URL = 'https://graph.qq.com/user/get_user_info'
+ OPEN_ID_URL = 'https://graph.qq.com/oauth2.0/me'
+ ICON_NAME = 'qq'
+
+ def __init__(self, access_token=None, openid=None):
+ config = self.get_config()
+ self.client_id = config.appkey if config else ''
+ self.client_secret = config.appsecret if config else ''
+ self.callback_url = config.callback_url if config else ''
+ super(QQOauthManager, self).__init__(access_token=access_token, openid=openid)
+
+ def get_authorization_url(self, nexturl='/'):
+ params = {
+ 'response_type': 'code',
+ 'client_id': self.client_id,
+ 'redirect_uri': self.callback_url + '&next_url=' + nexturl,
+ }
+ url = self.AUTH_URL + "?" + urllib.parse.urlencode(params)
+ return url
+
+ def get_access_token_by_code(self, code):
+ params = {
+ 'grant_type': 'authorization_code',
+ 'client_id': self.client_id,
+ 'client_secret': self.client_secret,
+ 'code': code,
+ 'redirect_uri': self.callback_url
+ }
+ rsp = self.do_get(self.TOKEN_URL, params)
+ if rsp:
+ d = urllib.parse.parse_qs(rsp)
+ token = d['access_token']
+ self.access_token = token
+ return token
+
+ def get_open_id(self):
+ if self.is_access_token_set:
+ params = {
+ 'access_token': self.access_token
+ }
+ rsp = self.do_get(self.OPEN_ID_URL, params)
+ if rsp:
+ rsp = rsp.replace('callback(', '').replace(')', '').replace(';', '')
+ obj = json.loads(rsp)
+ openid = str(obj['openid'])
+ self.openid = openid
+ return openid
+
+ def get_oauth_userinfo(self):
+ openid = self.get_open_id()
+ if openid:
+ params = {
+ 'access_token': self.access_token,
+ 'oauth_consumer_key': self.client_id,
+ 'openid': self.openid
+ }
+ rsp = self.do_get(self.API_URL, params)
+ logger.info(rsp)
+ obj = json.loads(rsp)
+ user = OAuthUser()
+ user.nikename = obj['nickname']
+ user.openid = openid
+ user.type = 'qq'
+ user.token = self.access_token
+ user.matedata = rsp
+ if 'email' in obj:
+ user.email = obj['email']
+ if 'figureurl' in obj:
+ user.picture = str(obj['figureurl'])
+ return user
+
+
def get_oauth_apps():
configs = OAuthConfig.objects.filter(is_enable=True).all()
if not configs:
diff --git a/requirements.txt b/requirements.txt
index d2c6e73..72b4e3b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,7 +2,7 @@ appdirs==1.4.3
asn1crypto==0.24.0
astroid==2.0.4
bottle==0.12.13
-certifi==2018.8.24
+certifi==2018.10.15
cffi==1.11.5
chardet==3.0.4
coverage==4.5.1
@@ -23,11 +23,11 @@ jsonpickle==1.0
lazy-object-proxy==1.3.1
markdown2==2.3.6
mccabe==0.6.1
-mistune==0.8.3
+mistune==0.8.4
olefile==0.46
packaging==18.0
Pillow==5.3.0
-pycparser==2.18
+pycparser==2.19
Pygments==2.2.0
pylint==2.1.1
PyMySQL==0.9.2
@@ -37,12 +37,12 @@ python-slugify==1.2.6
pytz==2018.5
raven==6.9.0
rcssmin==1.0.6
-requests==2.19.1
+requests==2.20.0
rjsmin==1.0.12
six==1.11.0
sqlparse==0.2.4
Unidecode==1.0.22
-urllib3==1.23
+urllib3==1.24
webencodings==0.5.1
WeRoBot==1.6.0
Whoosh==2.7.4
diff --git a/templates/oauth/bindsuccess.html b/templates/oauth/bindsuccess.html
index e664a75..4bee77c 100644
--- a/templates/oauth/bindsuccess.html
+++ b/templates/oauth/bindsuccess.html
@@ -13,9 +13,9 @@