Django之第三方平台QQ授权登录的实现
接入指南: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授权登录的实现的更多相关文章
- Android之QQ授权登录获取用户信息
有时候我们开发的app须要方便用户简单登录.能够让用户使用自己的qq.微信.微博登录到我们自己开发的app. 今天就在这里总结一下怎样在自己的app中集成QQ授权登录获取用户信息的功能. 首先我们打开 ...
- 在自己的网站上实现QQ授权登录
最近在实现QQ授权登录,现将我的实现过程以及我的理解整理如下.以下所述如有不对之处,请指正. 官方提供的SDK有:JS,PHP,Java.我的网站使用Scala+Play搭建的,所以只能用JS SDk ...
- iOS 基于第三方QQ授权登录
基于iOS实现APP的第三方QQ登陆.接入第三方SDK时的一个主要的步骤: 1,找到相关的开放平台.QQ互联平台,http://connect.qq.com/: 2,注冊成功后创建自己的APP.填写一 ...
- Django+wechatpy接入微信公众平台以及授权登录
确定Django环境可以正常运行,环境搭建见:Linux 搭建Nginx+uwsgi+Django环境 安装 wechatpy[cryptography] sudo pip3 install wech ...
- Django 利用第三方平台实现用户注册
前言: 登陆和注册功能是一个功能比较完善的网站必备的功能,其中涉及的业务逻辑实用性较强,所以我将Django的注册功能进行了总结,希望可以帮助大家.我们这次使用的第三方短息平台是云通信,当然你可以用其 ...
- QQ授权登录
这两天在做网站第三方登录,总结一下QQ登录吧,支付宝就不用了(下载dome把ID什么的换一换就基本可以了.),本文主要说的是代码的实现方式,逻辑部分主要还是根据帮助文档来的.不懂的同学可以先看看文档. ...
- Django 利用第三方平台实现用户注册02
前言: 上篇博客我们已经对设置了图形验证码,短信验证码对用户信息进行了一些简单的验证,本篇博客我们会将上篇的一些验证方法进行结合,来进一步完成我们的注册工作 1. 创建视图类 在user中的view创 ...
- SpringBoot基于JustAuth实现第三方授权登录
1. 简介 随着科技时代日渐繁荣,越来越多的应用融入我们的生活.不同的应用系统不同的用户密码,造成了极差的用户体验.要是能使用常见的应用账号实现全应用的认证登录,将会更加促进应用产品的推广,为生活 ...
- 解决微信公众号授权登录和开放平台微信第三方应用授权登录获取到的用户Openid关联问题
开发背景: 最近一段时间一直在做关于微信方面的网站应用开发,这段时间也收获的不少关于微信开发方面的开发技能,接触的比较多的主要有微信公众号和微信网站app第三方登录授权,以及微信会员卡,优惠券和扫描二 ...
- QQ第三方授权登录OAuth2.0实现(Java)
准备材料 1.已经备案好的域名 2.服务器(域名和服务器为统一主体或域名已接入服务器) 3.QQ号 4.开发流程:https://wiki.connect.qq.com/%E5%87%86%E5%A4 ...
随机推荐
- [转帖]ubuntu下配置iptables、ufw端口转发
iptables 端口转发(CentOS) 注意:一来一去 在中转服务器操作 iptables -t nat -A PREROUTING -p tcp --dport [端口号] -j DNAT -- ...
- [转帖]技术派-epoll和IOCP之比较
直入正题 Epoll 用于Linux系统: IOCP 是用于 Windows: Epoll 是当事件资源满足时发出可处理通知消息: IOCP 则是当事件完成时发出完成通知消息. 从应用程序的角度来看, ...
- 获取特定端口java进程的路径的shell脚本
获取特定端口java进程的路径的shell脚本 ll /proc/`lsof -i:5200 |grep ^java |awk '{print $2}' |uniq` |grep cwd |cut - ...
- 什么是根号?什么是 log ?
生日悖论是 \(O(\sqrt{n})\) 随机序列 LIS 是 \(O(\sqrt{n})\) 随机 \(\pm1\) 序列前缀和最大绝对值是 \(O(\sqrt{n})\) 证明 随机 Prufe ...
- 【第4个渗透靶机项目】 Tr0ll
每天都要加油哦! 0x00 信息搜集 首先找到一下靶机的ip,并扫描端口. 靶机和kali都是桥接. 那么先看一下kali的ifconfig信息. nmap -sn 192.168.0.0/24 ...
- 2021美亚杯团队赛write up
个人赛与团队赛下载文件解压密码:MeiyaCup2021 加密容器解密密码: uR%{)Y'Qz-n3oGU`ZJo@(1ntxp8U1+bW;JlZH^I4%0rxf;[N+eQ)Lolrw& ...
- KPlayer无人直播
KPlayer文档 其实就看这个教程就可以了: KPlayer文档 启动阿里云或者腾讯云的服务器进行这个步骤 服务器的购买链接: 腾讯云618 夏日盛惠_腾讯云年中优惠活动-腾讯云 域名特惠活动_域名 ...
- 利用Mybatis拦截器实现自定义的ID自增器
原生的Mybatis框架是没有ID自增器,但例如国产的Mybatis Plus却是支持,不过,Mybatis Plus却是缺少了自定属性的填充:例如:我们需要自定义填充一些属性,updateDate. ...
- ElasticSearch安装、插件介绍及Kibana的安装与使用详解
ElasticSearch安装.插件介绍及Kibana的安装与使用详解 1.安装 ElasticSearch 1.1 安装 JDK 环境 因为 ElasticSearch 是用 Java 语言编写的, ...
- 13.4 DirectX内部劫持绘制
相对于外部绘图技术的不稳定性,内部绘制则显得更加流程与稳定,在Dx9环境中,函数EndScene是在绘制3D场景后,用于完成将最终的图像渲染到屏幕的一系列操作的函数.它会将缓冲区中的图像清空,设置视口 ...