Content

Django之第三方平台QQ授权登录的实现(第三方qq登录接口异常)不要告诉别人

文章摘要

这篇文章介绍了使用Django框架在Python中实现QQ第三方认证登录的过程,涵盖了以下几个关键步骤: 1. **环境准备**:用户需要先创建QQ互联应用,并获取App ID和App Key。可以通过QQ互联官网或其他文档获取相关信息。 2. **创建和配置应用**:在Django的管理控制台中注册QQ应用,配置相关依赖项,包括设置应用的路径和名称,以及绑定QQ互联的开发文档。 3. **定义QQ登录模型类**:通过Django的数据库层定义`OAuthQQUser`模型类,用于关联QQ用户信息(openid)与Django的用户模型。 4. **使用QQLoginTool库**:文章建议使用第三方库QQLoginTool来简化QQ登录的实现,通过安装和配置该库,快速获取授权地址和处理认证流程。 5. **配置参数和URL路径**:在Django的settings.py中配置QQ登录的客户端 ID、客户端密钥和回调路径。同时,在urls.py中设置路由,实现QQ登录的URL配置。 6. **获取授权地址和认证流程**:通过QQLoginTool获取QQ登录的扫码页面地址,并通过获取Access Token和OpenID,实现用户的扫码登录。 7. **处理回调页面**:在回调页面中,用户需要提供授权码,文章详细介绍了如何使用QQLoginTool获取Access Token和OpenID,并处理可能的异常情况。 8. **用户绑定openid**:文章还介绍了如何将用户的openid与Django的用户关联起来,类似于用户注册的流程,包括必传参数验证、手机号合法性验证、密码校验和短信验证码验证。 9. **状态保持和登录绑定**:文章提到用户在登录时,系统会将用户名存入cookie中,以保持登录状态。 10. **签名与校验处理**:文章特别提到了使用`itsdangerous`库来对openid进行签名和校验,确保数据的安全性和有效性。 文章还提供了完整的代码示例,包括使用`QQAuthURLView`和`QQAuthUserView`处理授权和回调页面的逻辑,以及使用`OAuthQQ`对象获取tokens和openid的过程。这些代码示例可以帮助开发者快速上手实现QQ第三方认证登录功能。 总结来看,文章从创建QQ应用、配置开发环境,到使用第三方库实现认证流程,再到处理异常和状态保持,提供了全面的实现指南,适合需要在Django中集成QQ认证功能的开发者参考。


目录环境准备创建QQ互联应用创建应用模块定义QQ登录模型类执行迁移QQLoginTool库API使用说明QQ登录扫码页面认证获取openidopenid的判断处理openid是否绑定过用户openid已绑定用户openid未绑定用户openid签名处理openid绑定用户

创建一个QQ互联应用,并获取到App ID和App Key。

QQ互联官网:

开发文档:

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

python manage.py startapp oauth

在settings.py中注册应用

INSTALLED_APPS=[ # ‘django.contrib.admin’, ‘django.contrib.auth’, ‘django.contrib.contenttypes’, ‘django.contrib.sessions’, ‘django.contrib.messages’, ‘django.contrib.staticfiles’, ‘apps.user’, ‘apps.oauth’, ]

在settings.py同级目录下的urls.py设置路由

url(r’^’, include(‘apps.oauth.urls’,namespace=’oauth’)),

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

from django.db import models class OAuthQQUser(): “””QQ登录用户””” user=models.ForeignKey(‘user.User’, on_delete=models.CASCADE, verbose_name=’用户’) openid=models.CharField(max_length=64, verbose_name=’openid’, db_index=True) create_time=models.DateTimeField(auto_now_add=True, verbose_name=”创建时间”) update_time=models.DateTimeField(auto_now=True, verbose_name=”更新时间”) class Meta: db_table=’tb_oauth_qq’ verbose_name=’QQ登录用户’ verbose_name_plural=verbose_name

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

python manage.py makemigrations python manage.py migrate

腾讯QQ互联平台没有Python SDK,但是可以使用第三方封装好的SDK包,QQLoginTool是一个第三方库,封装了对接QQ互联的请求操作,可用于快速实现QQ登录的一种工具包。

安装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_CLIENT_ID=’1020343878′ QQ_CLIENT_SECRET=’Yu4123456LG0Yw53o’ QQ_REDIRECT_URI=’https://abc.com/oauth/callback’
from django.urls import re_path from . import views urlpatterns=[ re_path(r’^qq/login/$’, views.QQAuthURLView.as_view()), ]
from QQLoginTool.QQtool import OAuthQQ from django import http from django.conf import settings from django.views import View from utils.response_code import RETCODE “”” 提供QQ登录页面网址 https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=xxx&redirect_uri=xxx&state=xxx “”” class QQAuthURLView(View): def get(self, request): # next: 从哪个页面进入到的登录页面,登录成功后自动回到那个页面 next=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) login_url=oauth.get_qq_url() return http.JsonResponse({‘code’: 200 , ‘msg’: ‘OK’, ‘login_url’: login_url})
1.用户在QQ登录成功后,QQ会将用户重定向到配置的回调网址,同时会传递一个Authorization Code 2.拿到Authorization Code并完成OAuth2.0认证获取openid

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

from django.urls import re_path from . import views urlpatterns=[ re_path(r’^oauth/callback/$’, views.QQAuthUserView.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认证失败’) pass

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

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

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

try: oauth_user=OAuthQQUser.objects.get(openid=openid) except OAuthQQUser.DoesNotExist: # 如果openid没绑定用户 pass else: # 如果openid已绑定用户,实现状态保持 qq_user=oauth_user.user login(request, qq_user) # 响应结果 next=request.GET.get(‘state’) response=redirect(next) # 登录时用户名写入到cookie,有效期15天 response.set_cookie(‘username’, qq_user.username, max_age=3600 * 24 * 15) return response

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

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’: access_token} 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 }}”>

签名处理可以使用itsdangerous库,它是一个用于Python语言的库,提供了一些安全传输数据的工具类。其主要功能是在保证数据安全性的前提下,生成认证令牌、时间限制的令牌和加密/解密数据信息等。

安装itsdangerous

pip install itsdangerous

使用TimedJSONWebSignatureSerializer可以生成带有有效期的token

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer from django.conf import settings # serializer=Serializer(秘钥, 有效期秒) serializer=Serializer(settings.SECRET_KEY, 300) # serializer.dumps(数据), 返回bytes类型 token=serializer.dumps({‘mobile’: ‘18381234567’}) token=token.decode() # 检验token # 验证失败,会抛出itsdangerous.BadData异常 serializer=Serializer(settings.SECRET_KEY, 300) try: data=serializer.loads(token) except BadData: return None

生成openid签名与校验

from itsdangerous import BadData from itsdangerous import TimedJSONWebSignatureSerializer as Serializer from django.conf import settings def generate_eccess_token(openid): “”” 对openid签名 :param openid: 用户openid “”” serializer=Serializer(settings.SECRET_KEY, expires_in=3600) data={‘openid’: openid} token=serializer.dumps(data) return token.decode() def check_access_token(access_token): “”” 提取openid :param access_token: 签名后的openid “”” serializer=Serializer(settings.SECRET_KEY, expires_in=3600) try: data=serializer.loads(access_token) except BadData: return None else: return data.get(‘openid’)

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

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’) # 判断参数是否齐全 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(‘code’) sms_code_server=redis_conn.get(‘sms_%s’ % mobile) if sms_code_server is None: return render(request, ‘oauthCallback.html’, {‘msg’: ‘无效的短信验证码’}) if sms_code_client !=sms_code_server.decode(): return render(request, ‘oauthCallback.html’, {‘msg’: ‘输入短信验证码有误’}) # 判断openid是否有效 openid=check_access_token(access_token) if not openid: return render(request, ‘oauthCallback.html’, {‘msg’: ‘无效的openid’}) # 保存注册数据 try: user=User.objects.get(mobile=mobile) except User.DoesNotExist: # 用户不存在,新建用户 user=User.objects.create_user(username=mobile, password=password, mobile=mobile) else: # 如果用户存在,检查用户密码 if not user.check_password(password): return render(request, ‘oauthCallback.html’, {‘msg’: ‘用户名或密码错误’}) # 将用户绑定openid try: OAuthQQUser.objects.create(openid=openid, user=user) except DatabaseError: return render(request, ‘oauthCallback.html’, {‘msg’: ‘QQ登录失败’}) # 实现状态保持 login(request, user) # 响应绑定结果 next=request.GET.get(‘state’) response=redirect(next) # 登录时用户名写入到cookie,有效期15天 response.set_cookie(‘username’, user.username, max_age=3600 * 24 * 15) return response

到此这篇关于Django之第三方平台QQ授权登录的实现的文章就介绍到这了,更多相关Django 第三方平台QQ授权登录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:django 微信网页授权认证api的步骤详解django 微信网页授权登陆的实现