接入指南:https://wiki.connect.qq.com/成为开发者

准备工作

成为开发者

首先要有一个开发者账号,https://connect.qq.com/

登录后点击用户头像,修改个人信息

修改完信息后会提交系统审核,点击应用管理,可以看到审核状态,审核完毕后就可以创建应用了。(两三天的审核时间)

创建应用

https://wiki.connect.qq.com/__trashed-2

需要审核通过。应用图标必须是100px*100px大小的,否则不予通过。

功能实现

创建应用模块

创建一个新的应用oauth,用来实现QQ第三方认证登录的代码编写。

python manage.py startapp oauth

在settings.py中注册应用

INSTALLED_APPS = [
# ...
"oauth",
]

设置总路由urls.py

path('api/oauth/', include(('oauth.urls', 'oauth'), namespace='oauth')),

定义QQ登录模型类

在oauth/models.py中定义QQ身份(openid)与用户模型类User的关联关系

from django.db import models
class BaseModel(models.Model):
is_deleted = models.BooleanField(default=False, verbose_name="是否删除")
created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间") class Meta:
# 不创建该表(抽象模型类)
abstract = True class OAuthQQ(BaseModel):
user = models.ForeignKey("users.UserInfo", verbose_name="用户", on_delete=models.CASCADE)
openid = models.CharField(verbose_name="openid", max_length=64, db_index=True) class Meta:
db_table = "lg_oauth_qq"
verbose_name = "请求登录"
verbose_name_plural = verbose_name

执行迁移

执行迁移操作,生成QQ登录模型类对应的数据库表

python manage.py makemigrations
python manage.py migrate

QQLoginTool库

安装QQLoginTool

pip install QQLoginTool

导入

from QQLoginTool.QQtool import OAuthQQ

初始化OAuthQQ对象

oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET, redirect_uri=settings.QQ_REDIRECT_URI, state=next)

获取QQ登录扫码页面,扫码后得到Authorization Code

login_url = oauth.get_qq_url()

通过Authorization Code获取Access Token

access_token = oauth.get_access_token(code)

通过Access Token获取OpenID

openid = oauth.get_open_id(access_token)

在settings.py配置QQ登录参数

# QQ登录相关
QQ_CLIENT_ID = '102060113'
QQ_CLIENT_SECRET = '**********'
QQ_REDIRECT_URI = 'http://www.***.com/api/oauth/qq/callback/'

报错解决:

# 如果有以下报错,直接把源码放到项目里面即可
# ModuleNotFoundError: No module named 'QQLoginTool'

QQ登录扫码页面

from django.urls import path, re_path
from . import views urlpatterns = [
# qq登录地址
path("qq/login/", views.OAuthQQUrlView.as_view()),
]
from django.shortcuts import render
from django.views import View
from django import http
from django.conf import settings from QQLoginTool.QQtool import OAuthQQ from response_code import RETCODE, err_msg class OAuthQQUrlView(View):
def get(self, request):
# next: 从哪个页面进入到的登录页面,登录成功后自动回到那个页面
next_url = request.GET.get('next')
# 获取QQ登录页面网址
oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET,
redirect_uri=settings.QQ_REDIRECT_URI, state=next_url)
login_url = oauth.get_qq_url()
return http.JsonResponse({"code": RETCODE.OK, "msg": "成功", "login_url": login_url})

认证获取openid

1.用户在QQ登录成功后,QQ会将用户重定向到配置的回调网址,同时会传递一个Authorization Code

2.拿到Authorization Code并完成OAuth2.0认证获取openid

注意:回调网址在申请QQ登录开发资质时进行配置

from django.urls import path, re_path
from . import views urlpatterns = [
# qq登录地址
path("qq/login/", views.OAuthQQUrlView.as_view()),
# qq回调地址
path("qq/callback/", views.OAuthQQCallbacklView.as_view()), ]

使用code向QQ服务器请求,获取access_token

使用access_token向QQ服务器请求获取openid

"""用户扫码登录的回调处理"""
class QQAuthUserView(View):
def get(self, request):
"""Oauth2.0认证"""
# 提取code请求参数
code = request.GET.get('code')
if not code:
return http.HttpResponseBadRequest('缺少code')
# 创建oauth 对象
oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET,
redirect_uri=settings.QQ_REDIRECT_URI)
try:
# 使用code向QQ服务器请求access_token
access_token = oauth.get_access_token(code)
# 使用access_token向QQ服务器请求openid
openid = oauth.get_open_id(access_token)
except Exception as e:
logger.error(e)
return http.HttpResponseServerError('OAuth2.0认证失败')

openid的判断处理

openid是否绑定过用户

判断openid是否绑定过用户,只需要使用openid查询该QQ用户是否绑定过用户即可。

oauth_user = OAuthQQUser.objects.get(openid=openid)

openid已绑定用户

如果openid已绑定用户,直接生成状态保持信息,登录成功,并重定向到首页。

from django.shortcuts import render, redirect
from django.views import View
from django import http
from django.conf import settings
from django.contrib.auth import login from QQLoginTool.QQtool import OAuthQQ from response_code import RETCODE, err_msg
from logger import log
from .models import OAuthQQ as OAuthQQUser try:
oauth_user = OAuthQQUser.objects.get(openid=openid)
except OAuthQQUser.DoesNotExist:
# 如果openid没有绑定用户
pass
else:
# 如果openid已绑定用户
# 登录
login(request, oauth_user.user)
# 响应结果
next_url = request.GET.get("next")
# 页面跳转
response = redirect(next_url)
# 状态保持
response.set_cookie('username', oauth_user.user.username, settings.SESSION_COOKIE_AGE)
return response

openid未绑定用户

openid属于用户隐私信息,在后续的绑定用户操作中前端会使用openid,因此需要将openid签名处理,避免暴露。

from authlib_jwt import generate_access_token

try:
oauth_user = OAuthQQUser.objects.get(openid=openid)
except OAuthQQUser.DoesNotExist:
# 如果openid没绑定用户 generate_eccess_token:对openid签名
access_token = generate_eccess_token(openid)
context = {'access_token_openid': access_token.decode()}
return render(request, 'oauthCallback.html', context)
else:
qq_user = oauth_user.user
login(request, qq_user)
response = redirect(reverse('contents:index'))
response.set_cookie('username', qq_user.username, max_age=3600 * 24 * 15)
return response

oauthCallback.html中渲染access_token

<input type="hidden" name="access_token" value="{{ access_token }}">

openid签名处理

签名处理可以使用authlib库

pip install authlib
from authlib.jose import jwt, JoseError

def generate_access_token(openid):
"""
加密函数
:param openid: 加密的数据
:return: 加密后的数据
"""
# 签名算法
header = {'alg': 'HS256'}
# 待签名的数据负载
data = {"openid": openid}
# 生成token
token = jwt.encode(header=header, payload=data, key=settings.SECRET_KEY)
return token def check_access_token(openid):
"""
校验authlib签名函数
:param openid: 加密后的token
:return: user对象或None
"""
try:
data = jwt.decode(openid, settings.SECRET_KEY)
except JoseError:
return None
else:
# 拿到解密后的数据
return data.get("openid")

openid绑定用户

openid绑定用户的过程类似于用户注册的业务逻辑

import re

from django.shortcuts import render, redirect
from django.views import View
from django import http
from django.conf import settings
from django.contrib.auth import login from django_redis import get_redis_connection from QQLoginTool.QQtool import OAuthQQ
from response_code import RETCODE
from logger import log
from .models import OAuthQQ as OAuthQQUser
from users.models import UserInfo
from authlib_jwt import generate_access_token, check_access_token class QQAuthUserView(View):
"""用户扫码登录的回调处理"""
def get(self, request):
"""Oauth2.0认证"""
......
def post(self, request):
"""用户绑定openid"""
# 接收参数
mobile = request.POST.get('mobile')
password = request.POST.get('password')
sms_code_client = request.POST.get('sms_code')
access_token = request.POST.get('access_token_openid')
# 判断参数是否齐全
if not all([mobile, password, sms_code_client]):
return http.HttpResponseBadRequest('缺少必传参数')
# 判断手机号是否合法
if not re.match(r'^1[3-9]\d{9}$', mobile):
return http.HttpResponseBadRequest('请输入正确的手机号码')
# 判断密码是否合格
if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
return http.HttpResponseBadRequest('请输入8-20位的密码')
# 判断短信验证码是否一致
redis_conn = get_redis_connection('verifications')
sms_code_server = redis_conn.get('sms_code_%s' % mobile)
if sms_code_server is None:
return render(request, 'oauth_callback.html', {'msg': '无效的短信验证码'})
if sms_code_client != sms_code_server.decode():
return render(request, 'oauth_callback.html', {'msg': '输入短信验证码有误'})
# 判断openid是否有效
openid = check_access_token(access_token)
if not openid:
return render(request, 'oauth_callback.html', {'msg': '无效的openid'})
# 保存注册数据
try:
user = UserInfo.objects.get(mobile=mobile)
except UserInfo.DoesNotExist:
# 不存在,则创建新用户
try:
user = UserInfo.objects.create_user(username=mobile, mobile=mobile, password=password)
except Exception as e:
log.error(e)
return render(request, 'oauth_callback.html', {'msg': '创建用户失败.'})
else:
if not user.check_password(password):
return render(request, 'oauth_callback.html', {'msg': '密码错误.'})
# 将用户绑定openid
try:
OAuthQQUser.objects.create(user=user, openid=openid)
except Exception as e:
log.error(e)
return render(request, 'oauth_callback.html', {'msg': 'QQ登录失败.'})
# 实现状态保持
login(request, user)
# 响应绑定结果
state = request.GET.get('state')
# 页面跳转
response = redirect(state)
# 写入cookie
response.set_cookie('username', user.username, settings.SESSION_COOKIE_AGE)
return response

Django之第三方平台QQ授权登录的实现的更多相关文章

  1. Android之QQ授权登录获取用户信息

    有时候我们开发的app须要方便用户简单登录.能够让用户使用自己的qq.微信.微博登录到我们自己开发的app. 今天就在这里总结一下怎样在自己的app中集成QQ授权登录获取用户信息的功能. 首先我们打开 ...

  2. 在自己的网站上实现QQ授权登录

    最近在实现QQ授权登录,现将我的实现过程以及我的理解整理如下.以下所述如有不对之处,请指正. 官方提供的SDK有:JS,PHP,Java.我的网站使用Scala+Play搭建的,所以只能用JS SDk ...

  3. iOS 基于第三方QQ授权登录

    基于iOS实现APP的第三方QQ登陆.接入第三方SDK时的一个主要的步骤: 1,找到相关的开放平台.QQ互联平台,http://connect.qq.com/: 2,注冊成功后创建自己的APP.填写一 ...

  4. Django+wechatpy接入微信公众平台以及授权登录

    确定Django环境可以正常运行,环境搭建见:Linux 搭建Nginx+uwsgi+Django环境 安装 wechatpy[cryptography] sudo pip3 install wech ...

  5. Django 利用第三方平台实现用户注册

    前言: 登陆和注册功能是一个功能比较完善的网站必备的功能,其中涉及的业务逻辑实用性较强,所以我将Django的注册功能进行了总结,希望可以帮助大家.我们这次使用的第三方短息平台是云通信,当然你可以用其 ...

  6. QQ授权登录

    这两天在做网站第三方登录,总结一下QQ登录吧,支付宝就不用了(下载dome把ID什么的换一换就基本可以了.),本文主要说的是代码的实现方式,逻辑部分主要还是根据帮助文档来的.不懂的同学可以先看看文档. ...

  7. Django 利用第三方平台实现用户注册02

    前言: 上篇博客我们已经对设置了图形验证码,短信验证码对用户信息进行了一些简单的验证,本篇博客我们会将上篇的一些验证方法进行结合,来进一步完成我们的注册工作 1. 创建视图类 在user中的view创 ...

  8. SpringBoot基于JustAuth实现第三方授权登录

    1. 简介   随着科技时代日渐繁荣,越来越多的应用融入我们的生活.不同的应用系统不同的用户密码,造成了极差的用户体验.要是能使用常见的应用账号实现全应用的认证登录,将会更加促进应用产品的推广,为生活 ...

  9. 解决微信公众号授权登录和开放平台微信第三方应用授权登录获取到的用户Openid关联问题

    开发背景: 最近一段时间一直在做关于微信方面的网站应用开发,这段时间也收获的不少关于微信开发方面的开发技能,接触的比较多的主要有微信公众号和微信网站app第三方登录授权,以及微信会员卡,优惠券和扫描二 ...

  10. QQ第三方授权登录OAuth2.0实现(Java)

    准备材料 1.已经备案好的域名 2.服务器(域名和服务器为统一主体或域名已接入服务器) 3.QQ号 4.开发流程:https://wiki.connect.qq.com/%E5%87%86%E5%A4 ...

随机推荐

  1. 【转帖】bpftrace 指南

    文章目录 0. bpftrace 0.1 bpftrace组件 0.2 bpftrace 帮助信息 0.3 bpftrace 工具速览表 0.4 bpftrace 探针 0.4.1 tracepoin ...

  2. [转帖]学习linux必须知道的命令

    https://www.cnblogs.com/aibeier/p/15315487.html 基础不牢,地动山摇.在linux命令行下查看命令帮助man用于查看命令的帮助信息 man cp--hel ...

  3. 一个PCI-E的硬盘参数

    看了下 HDD 随机 IOPS 在 100-200 之间 (读写) SATA的 SSD 随机IOPS 在 读 100k 写 20k 左右U.2的SSD 的随机IOPS 在 读 500k 写 50k 左 ...

  4. 手工创建一个带sticky模块的nginx镜像 并且实现容器化负载均衡的方法

    最近想进行容器化运行的nginx反向代理负载均衡服务. 找了一下 dockerhub上面的 nginx 发现里面不包含 sticky模块. 会报错为: nginx: [emerg] unknown d ...

  5. JVM内存初步学习

    JVM内存初步学习   最近在学习容器内的JVM运行, 简单总结了下学习结果, 但是感觉还是分不清楚很多地方: 同事帮忙进行了 native memory的监控, 主要信息简要如下: jvm刚运行起来 ...

  6. Unity下调试ToLua(基于IDEA和VSCode)

    公司移动端项目是基于Unity的,底层支持由C#提供,上层Lua调用C#中注册的函数支持来做业务逻辑,框架用的是ToLua.开始做移动端有一段时间了,一直都觉得调试代码是个很蛋疼的体验:几乎都是靠肉眼 ...

  7. elementui出现展开后子菜单宽度多出1px问题

    添加 就可以解决了 .el-menu { border-right-width: 0; } <template> <div class="compen-left-men&q ...

  8. (数据科学学习手札157)pandas新增case_when方法

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 大家好我是费老师,pandas在前不久更新的2. ...

  9. electron-builder

    electron-builder打包工具 首先,确保你的项目中已经安装了 electron-builder.可以在项目根目录下运行以下命令来安装它: npm install electron-buil ...

  10. 利用Mybatis拦截器实现自定义的ID自增器

    原生的Mybatis框架是没有ID自增器,但例如国产的Mybatis Plus却是支持,不过,Mybatis Plus却是缺少了自定属性的填充:例如:我们需要自定义填充一些属性,updateDate. ...