django web网站实现第三方QQ登录

第一步:成为开发者

成为QQ互联的开发者,审核通过才可实现;审核通过后要创建应用,即获取本项目对应与QQ互联的应用ID。
QQ登录开发文档:http://wiki.connect.qq.com/准备工作_oauth2-0

第二步:配置参数

成为开发者之后,再django的setting.py文件中配置QQ登录参数

QQ_CLIENT_ID = ''  # appid
QQ_CLIENT_SECRET = ''  # appkey
QQ_REDIRECT_URI = 'http://127.0.0.1:8080/XXX.html'  # 跳转url

然后创建一个新的应用oauth,用来实现QQ第三方认证登录,并注册到
INSTALLED_APPS = ['oauth.apps.oauthConfig',]
设置总路由前缀为 oauth/
在utils/models.py文件中创建模型类基类,用于增加数据新建时间和更新时间

from django.db import models


class BaseModel(models.Model):
    """为模型类补充字段"""
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        abstract = True  # 说明是抽象模型类, 用于继承使用,数据库迁移时不会创建BaseModel的表

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

from django.db import models
from utils.models import BaseModel
class OAuthQQUser(BaseModel):
    # 定义QQ身份(openid)与用户模型类User的关联关系
    user = models.ForeignKey('users.User', on_delete=models.CASCADE, verbose_name='用户')
    openid = models.CharField(max_length=64, verbose_name='openid', db_index=True)
    
    class Meta:
        db_table = 'oauth_qq'
        verbose_name = 'QQ用户数据'
        verbose_name_plural = verbose_name

第三步:QQ登录扫码页面

提供QQ登录扫码页面网址https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=xxx&redirect_uri=xxx&state=xxx
在这里插入图片描述
pip install QQLoginTool 安装qq登录工具
这个集成了QQ辅助类,可以让自己少些写代码,方便调用,这里贴一点它的源代码

from django.conf import settings
from urllib.parse import urlencode, parse_qs
import json
import requests


class OAuthQQ(object):
   """
   QQ认证辅助工具类
   """

   def __init__(self, client_id=None, client_secret=None, redirect_uri=None, state=None):
       self.client_id = client_id 
       self.client_secret = client_secret 
       self.redirect_uri = redirect_uri
       self.state = state   # 用于保存登录成功后的跳转页面路径

   def get_qq_url(self):
       # QQ登录url参数组建
       data_dict = {
           'response_type': 'code',
           'client_id': self.client_id,
           'redirect_uri': self.redirect_uri,
           'state': self.state
       }

       # 构建url
       qq_url = 'https://graph.qq.com/oauth2.0/authorize?' + urlencode(data_dict)

       return qq_url

   # 获取access_token值
   def get_access_token(self, code):
       # 构建参数数据
       data_dict = {
           'grant_type': 'authorization_code',
           'client_id': self.client_id,
           'client_secret': self.client_secret,
           'redirect_uri': self.redirect_uri,
           'code': code
       }

       # 构建url
       access_url = 'https://graph.qq.com/oauth2.0/token?' + urlencode(data_dict)

       # 发送请求
       try:
           response = requests.get(access_url)

           # 提取数据
           # access_token=FE04************************CCE2&expires_in=7776000&refresh_token=88E4************************BE14
           data = response.text

           # 转化为字典
           data = parse_qs(data)
       except:
           raise Exception('qq请求失败')

       # 提取access_token
       access_token = data.get('access_token', None)

       if not access_token:
           raise Exception('access_token获取失败')

       return access_token[0]

   # 获取open_id值

   def get_open_id(self, access_token):

       # 构建请求url
       url = 'https://graph.qq.com/oauth2.0/me?access_token=' + access_token

       # 发送请求
       try:
           response = requests.get(url)

           # 提取数据
           # callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} );
           # code=asdasd&msg=asjdhui  错误的时候返回的结果
           data = response.text
           data = data[10:-3]
       except:
           raise Exception('qq请求失败')
       # 转化为字典
       try:
           data_dict = json.loads(data)
           # 获取openid
           openid = data_dict.get('openid')
       except:
           raise Exception('openid获取失败')

       return openid

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

from itsdangerous import TimedJSONWebSignatureSerializer as TJS
from django.conf import settings

# tjs= TJS(秘钥, 有效期秒)
tjs= TJS(settings.SECRET_KEY, 300)
# tjs.dumps(数据), 返回bytes类型
token = tjs.dumps({'mobile': '18512345678'})
token = token.decode()

# 检验token
# 验证失败,会抛出itsdangerous.BadData异常
tjs= TJS(settings.SECRET_KEY, 300)
try:
    data = tjs.loads(token)
except BadData:
    return None

第四步:获取QQ用户OpenID

扫码成功后,要准备一个回调页面,这里就不做详细的讲解,下面就是获取QQ用户OpenID,
在QQ将用户重定向到此网页的时候,重定向的网址会携带QQ提供的code参数,用于获取用户信息使用,我们需要将这个code参数发送给后端,在后端中使用code参数向QQ请求用户的身份信息,并查询与该QQ用户绑定的用户。

from QQLoginTool.QQtool import OAuthQQ
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from django.conf import settings
from rest_framework_jwt.settings import api_settings
from oauth.models import OAuthQQUser
from itsdangerous import TimedJSONWebSignatureSerializer as TJS
from oauth.serializers import OauthSerializers

class QQAuthUserView(APIView):
    """用户扫码登录的回调处理"""

    def get(self, request):
        # 提取code请求参数
        code = request.query_params.get('code')
        if not code:
            return Response({'message': '缺少code'}, status=status.HTTP_400_BAD_REQUEST)

        # 创建qq对象
        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:
            return Response({'message': 'QQ服务异常'}, status=status.HTTP_503_SERVICE_UNAVAILABLE)

        # 使用openid查询该QQ用户是否绑定过用户
        try:
            oauth_user = OAuthQQUser.objects.get(openid=openid)
        except OAuthQQUser.DoesNotExist:
            # 如果openid没绑定用户,创建用户并绑定到openid
            # 为了能够在后续的绑定用户操作中前端可以使用openid,在这里将openid签名后响应给前端
            tjs = TJS(settings.SECRET_KEY, 300)   # 使用TimedJSONWebSignatureSerializer生成带有有效期的token
            open_id = tjs.dumps({'openid': openid}).decode()

            return Response({'access_token': open_id})
        else:
            # 如果openid已绑定用户,直接生成JWT token,并返回
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

            # 获取oauth_user关联的user
            user = oauth_user.user
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)

            response = Response({
                'token': token,
                'user_id': user.id,
                'username': user.username
            })

            return response

    def post(self, request):
        # 1、获取前端数据
        data = request.data
        # 2、验证数据
        ser = OauthSerializers(data=data)
        ser.is_valid()
        print(ser.errors)
        # 3、绑定保存数据
        ser.save()
        # 4、返回结果
        return Response(ser.data)

根据openid查询用户,如果能够查询到用户,就直接生成状态保持信息,登录到网站
如果不能查询到用户,就直接将OpenID序列化并返回给前端,用于后续的绑定网站用户操作。

第五步:openid绑定用户

用户需要填写手机号、密码、短信验证码
如果用户未在此网站注册过,则会将手机号作为用户名为用户创建一个网站账户,并绑定用户
如果用户已在此网站注册过,则检验密码后直接绑定用户

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值