学习
实践
活动
工具
TVP
写文章

Python3.6与Django2实现QQ第三方账号登录

这一篇教程,我们一起使用Python3.6与Django2实现QQ第三方账号登录。

首先,如果想使用QQ第三方登录功能,需要先在QQ互联(https://connect.qq.com/)进行开发者认证。

认证审核通过后,创建一个新的网站应用,并提交审核。

网站应用审核通过后,我们能够的到应用的APP ID和APP Key。

另外,网站应用的回调地址建议先修改为:http://127.0.0.1:8888/login,以方便我们编程过程中进行调试。

有了网站应用的APP ID、APP Key以及回调地址,我们就可以开始编写代码了。

在调用QQ的第三方登录之前,我们先做一些准备工作。

一、创建一个Django项目,并创建应用(例如:website)。

二、进行项目设置。

示例代码:(settings.py)

INSTALLED_APPS = [ ...省略部分代码... 'website',]DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'website', 'USER':'root', 'PASSWORD':'Opython.com666', 'HOST':'127.0.0.1', 'PORT':'3306', }}STATIC_ROOT=os.path.join(BASE_DIR, 'static')

三、创建数据库与数据模型,通过模型生成数据表。

示例代码:(models.py)

from django.db import modelsclass User(models.Model): nickname = models.CharField('昵称', max_length=150) openid = models.CharField('ID', max_length=128, primary_key=True) head = models.URLField('头像') gender = models.CharField('性别', max_length=2, default='保密')

完成模型类的创建后,执行“makemigrations”和“migrate”命令进行数据表的创建。

如果执行命令时发生错误,可以尝试先通过MySQL命令创建数据库,命令中声明字符集为“utf8”。

然后,再重新执行“makemigrations”和“migrate”命令。

四、添加QQ登录图标素材。

在应用目录“website”下创建新的文件夹“static”,并在“static”文件夹下创建文件夹“images”,将QQ登录的图标存放在“images”文件夹中。

五、创建登录页面模板文件。

示例代码:(login.html)

登录{% load static %} {% if userinfo %} {{ userinfo.nickname }} {% else %} {% endif %}

上述代码中,如果登录之后(存在用户信息),显示用户头像和昵称;否则(不存在用户信息),显示登录图标,可以点击进行登录。

六、创建视图函数。

示例代码:(views.py)

七、配置URL分发

示例代码:(urls.py)

完成以上准备工作之后,运行开发服务器即能够进行登录页面的访问。

接下来,我们完成QQ第三方登录的关键代码。

QQ第三方登录需要经过以下过程:

网站应用获取用户授权码(打开登录页面)

通过授权码获取访问令牌(Access Token)

通过访问令牌获取QQ用户的openid

通过openid和访问令牌获取用户信息

1、网站应用获取用户授权码

在模板“index.html”中我们为QQ登录图片添加了链接“to_login/”,我们在视图中编写这个链接对应的函数。

示例代码:(views.py)

from django.shortcuts import HttpResponseRedirectfrom urllib import parseimport random

def to_login(request): state = str(random.randrange(100000, 999999)) # 定义一个随机状态码,防止跨域伪造攻击。 request.session['state'] = state # 将随机状态码存入Session,用于授权信息返回时验证。 client_id = '1*******9' # QQ互联中网站应用的APP ID。 callback = parse.urlencode({'redirect_uri': 'http://127.0.0.1:8888/login'}) # 对回调地址进行编码,用户同意授权后将调用此链接。 login_url = 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=%s&%s&state=%s' % ( client_id, callback, state) # 组织QQ第三方登录链接 return HttpResponseRedirect(login_url) # 重定向到QQ第三方登录授权页面

示例代码:(urls.py)

path('to_login/', site_view.to_login),

2、通过授权码获取访问令牌(Access Token)

当用户在QQ登录界面中同意授权后,此时会打开回调地址并带有授权码的参数“code”。

此时浏览器地址栏显示类似“http://127.0.0.1:8888/login/?code=C84FEE1CBE828DE5CA8BEF973E1E0FE0&state=613473”的地址。

我们需要一个视图函数对“login/”这个URL进行处理,通过参数“code”获取访问令牌。

示例代码:(urls.py)

path('login/', site_view.login),

示例代码:(views.py)

from django.shortcuts import HttpResponsefrom urllib import request as reqimport reimport json

def login(request): if request.session['state'] == request.GET['state']: # 验证状态码,防止跨域伪造攻击。 code = request.GET['code'] # 获取用户授权码 client_id = '1*******9' # QQ互联中网站应用的APP ID。 client_secret = '83b76c870************9ec664b8891' # QQ互联中网站应用的APP Key。 callback = parse.urlencode({'redirect_uri': 'http://127.0.0.1:8888/login'}) # 对回调地址进行编码,用户同意授权后将调用此链接。 login_url = 'https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&code=%s&client_id=%s&client_secret=%s&%s' % ( code, client_id, client_secret, callback) # 组织获取访问令牌的链接 response = req.urlopen(login_url).read().decode() # 打开获取访问令牌的链接 ...接下一段代码...

打开获取访问令牌的链接之后,获取到的返回数据类似:

access_token=28BEF57C************622BC866E90&expires_in=7*****0&refresh_token=4D24F259****************AD146768

3、通过访问令牌获取QQ用户的openid

在上一步的返回数据中,我们能看到第一部分就是访问令牌,我们可以提取这个令牌内容,作为获取QQ用户openid的参数。

示例代码:(接上一段代码)

access_token = re.split('&', response)[0] # 获取访问令牌res = req.urlopen('https://graph.qq.com/oauth2.0/me?' + access_token).read().decode() # 打开获取openid的链接...接下一段代码...

打开获取openid的链接之后,获取到的返回数据类似:

callback( {“client_id”:”1*******9″,”openid”:”0D2DC10E****************66E1F801″} );

为了获取返回数据中的openid,我们可以单独写一个函数进行解析。

def parse_jsonp(jsonp_str): try: return re.search('^[^(]*?\((.*)\)[^)]*$', jsonp_str).group(1) except: raise ValueError('无效数据!')

4、通过openid和访问令牌获取用户信息

此时,我们已经获取了访问令牌和openid,就能够进行用户信息的获取了。

示例代码:(接上一段代码)

openid = json.loads(parse_jsonp(res))['openid'] # 从返回数据中获取openid userinfo = req.urlopen('https://graph.qq.com/user/get_user_info?oauth_consumer_key=%s&openid=%s&%s' % ( client_id, openid, access_token)).read().decode() # 打开获取用户信息的链接 userinfo = json.loads(userinfo) # 将返回的用户信息数据(JSON格式)读取为字典。 user = User.objects.get(openid=openid) # 查询是否已存在用户 if not user: # 如果不存在用户 user = User() # 创建新用户 user.openid = openid # 写入用户信息 user.nickname = userinfo['nickname'] # 写入用户信息 user.gender = userinfo['gender'] # 写入用户信息 user.head = userinfo['figureurl_qq_1'] # 写入用户信息 user.save() # 保存或更新用户 request.session['openid'] = openid # 将已登录的用户openid写入Session return render(request, 'index.html', {'userinfo': user})else: return HttpResponse('授权失败!')

注意:获取的用户信息为JSON格式,包含了很多用户信息内容,可以读取为字典然后获取相关信息。

关于能够获取到的用户信息,可以参考:http://wiki.connect.qq.com/get_user_info

另外,本教程中未对可能出现的异常进行处理(例如获取用户信息失败,可以根据返回的错误码进行处理),仅做正常登录过程参考。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180607A0ID6C00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码关注腾讯云开发者

领取腾讯云代金券