跳转到主内容
极星编程网:以代码为星,赴技术山海!

Django之第三方平台QQ授权登录的实现

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

QQ互联官网:

https://connect.qq.com/

开发文档:

https://wiki.connect.qq.com/创建应用模块创建一个新的应用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')),定义QQ登录模型类在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 migrateQQLoginTool库腾讯QQ互联平台没有Python SDK,但是可以使用第三方封装好的SDK包,QQLoginTool是一个第三方库,封装了对接QQ互联的请求操作,可用于快速实现QQ登录的一种工具包。

安装QQLoginToolpip install QQLoginToolAPI使用说明导入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 Codelogin_url = oauth.get_qq_url()通过Authorization Code获取Access Tokenaccess_token = oauth.get_access_token(code)通过Access Token获取OpenIDopenid = 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'QQ登录扫码页面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})认证获取openid1.用户在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认证失败') passopenid的判断处理openid是否绑定过用户判断openid是否绑定过用户,只需要使用openid查询该QQ用户是否绑定过用户即可。

oauth_user = OAuthQQUser.objects.get(openid=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 responseopenid未绑定用户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 responseoauthCallback.html中渲染access_tokenopenid签名处理签名处理可以使用itsdangerous库,它是一个用于Python语言的库,提供了一些安全传输数据的工具类。其主要功能是在保证数据安全性的前提下,生成认证令牌、时间限制的令牌和加密/解密数据信息等。

安装itsdangerouspip install itsdangerous使用TimedJSONWebSignatureSerializer可以生成带有有效期的tokenfrom 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绑定用户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 微信网页授权登陆的实现

相关文章