最新消息:欢迎光临 魔力 • Python!大家可以点开导航菜单中的【学习目录】,这个目录类似图书目录,更加方便学习!

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

Django教程 小楼一夜听春语 6098浏览 0评论

这一篇教程,我们一起使用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 models

class 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”。

mysql>CREATE DATABASE website DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

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

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

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

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

示例代码:(login.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
{% load static %} <!--加载静态文件目录-->
{% if userinfo %} <!--如果存在用户信息-->
    <img src="{{ userinfo.head }}">{{ userinfo.nickname }} <!--显示头像与昵称-->
{% else %} <!--否则-->
    <a href="to_login/"><img src="{% static '/images/qq.png' %}"></a>  <!--显示登录图标-->
{% endif %}
</body>
</html>

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

六、创建视图函数。

示例代码:(views.py)

from django.shortcuts import render
from .models import User

def index(request):
    try:
        openid = request.session['openid']  # 读取Session
        userinfo = User.objects.get(openid=openid)  # 根据Session获取用户信息
        return render(request, 'index.html', {'userinfo': userinfo})
    except:  # 如果发生异常
        return render(request, 'index.html')

七、配置URL分发

示例代码:(urls.py)

from django.contrib import admin
from django.urls import path
from website import views as site_view

urlpatterns = [
    path('',site_view.index),
    path('admin/', admin.site.urls),
]

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

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

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

  • 网站应用获取用户授权码(打开登录页面)
  • 通过授权码获取访问令牌(Access Token)
  • 通过访问令牌获取QQ用户的openid
  • 通过openid和访问令牌获取用户信息

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

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

示例代码:(views.py)

from django.shortcuts import HttpResponseRedirect
from urllib import parse
import 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 HttpResponse
from urllib import request as req
import re
import 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

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

 

 

转载请注明:魔力Python » Python3.6与Django2实现QQ第三方账号登录

头像
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网站 (可选)

网友最新评论 (1)

  1. 头像
    好教程,通俗易懂,感谢小楼老师的分享~ 😳
    行走中的码农4年前 (2019-11-24)回复