接入指南: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. [转帖]【测试】 FIO:ceph/磁盘IO测试工具 fio(iodepth深度)

    目录 随看随用 NAS文件系统测试 块系统测试 FIO用法 FIO介绍 FIO 工具常用参数: FIO结果说明 I/O 的重放('录'下实际工况的IO,用fio'重放') fio工作参数可以写入配置文 ...

  2. [转帖]UTF8 和 AL32UTF8 的区别

    本文章向大家介绍UTF8 和 AL32UTF8 的区别,主要内容包括 .使用实例.应用技巧.基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下.  UTF8 和 AL32UTF8 ...

  3. [转帖]三星研发出首个基于存算一体技术的GPU大型计算系统 (收录于存算一体芯片赛道投资融资分析)

    https://zhuanlan.zhihu.com/p/591850021 陈巍谈芯:产业巨头已经打通存算一体技术的落地通道,存算一体技术加快应用部署.与未使用HBM-PIM(HBM-PIM GPU ...

  4. UOS可能的来源

    1050a 行业版 是基于 阿里的Anolis 1050d 企业版 是基于debian 1050e 欧拉版 是基于华为欧拉 euler

  5. Python设计模式:你的代码真的够优雅吗?

    当涉及到代码优化时,Python作为一种高级编程语言,具有广泛的应用领域和强大的功能.在软件开发中,设计模式是一种被广泛采用的解决问题的方案,它提供了一种在特定情境中重复使用的可行方案.在Python ...

  6. 【代码分享】使用 terraform, 在 ZeroSSL 上申请托管在 cloudflare 上的域名对应的证书

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 接上一篇:<使用 terraform, 在 Let' ...

  7. 如何减缓vm中慢插入的次数

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 偶然发现vm-storage的监控里有这样一个指标:vm_ ...

  8. python中,Microsoft Visual C++ 14.0 or greater is required问题解决方案

    今天在写一个小程序,安装依赖的时候发现这个问题,平时都是直接安装Visual Studio解决,但是这个安装太大了,所以解决看看怎么安装是最方便的,最容易解决的. 下面这个就是出现的问题: build ...

  9. apb vnext DynamicCient

    1.在需要的服务客户端(xx.HttpApi.Client)Nuget 引用和模块依赖 引用:VOLO.APB.HTTP.CLENT [dependsOn(typeof(AbpHttpClientMo ...

  10. 微信小程序-页面生命周期

    官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/app-service/page-life-cycle.html