zoukankan      html  css  js  c++  java
  • django项目之 集成QQ三方登录

    一、流程图

    二、新建一个单独的三方登录模型,用于以后集中使用三方登录

      官方文档:https://wiki.connect.qq.com/oauth2-0%E5%BC%80%E5%8F%91%E6%96%87%E6%A1%A3

      操作流程按照如下步骤进行即可:

    三、代码部分:前端按钮部分不处理,本文只负责后端的接口:

      1、请求https://graph.qq.com/oauth2.0/authorize接口,参数和请求方法见官方文档,获取access_token

    # 再utils文件中定义,方便后续代码的迁移或者框架改造后的复用

    from django.conf import settings
    from urllib.parse import urlencode, parse_qs
    from urllib.request import urlopen
    import json
    import logging

    
    

    logger = logging.getLogger("django")

    
    


    class QQErrorExcept(Exception):
    """自定义一个QQ异常类"""
    pass

    
    


    class OauthQQ():
    """QQ的辅助类工具,单独封装"""

    
    

    def __init__(self, app_key=None, appid=None, redirect_uri=None, state=None):
    self.app_key = app_key or settings.QQ_APP_KEY
    self.appid = appid or settings.QQ_APP_ID
    self.redirect_uri = redirect_uri or settings.QQ_REDIRECT_URL
    self.state = state or settings.QQ_STATE

    
    

    def get_QQ_url(self):
    """用于获取QQ的链接,返回给客户端调用获取access_token"""
    params = {
    "response_type": "code",
    "client_id": self.appid,
    "redirect_uri": self.redirect_uri,
    "state": self.state,
    "scope": "get_user_info"
    }
    url = "https://graph.qq.com/oauth2.0/authorize?" + urlencode(params)
    return url

    
    

    def get_QQ_access_token(self, code, state=None):
    """
    根据授权码,获取临时票据access_token
    :param code: 前段获取到并传给后端的authencation code
    :param state: 回调参数
    :return:
    """
    params = {
    "grant_type": "authorization_code",
    "client_id": self.appid,
    "client_secret": self.app_key,
    "code": code,
    "redirect_uri": self.redirect_uri
    }
    url = "https://graph.qq.com/oauth2.0/token?" + urlencode(params)
    try:
    response = urlopen(url)
    response_data = response.read().decode()
    # parse_qs 把查询字符串格式的内容转换成字典[注意:转换后的字典,值是列表格式]
    data = parse_qs(response_data)
    access_token = data.get("access_token")[0]
    expires_in = data.get("expires_in")[0]
    refresh_token = data.get("refresh_token")[0]
    except:
    logger.error('code=%s msg=%s' % (data.get("code"), data.get('msg')))
    raise QQErrorExcept
    return access_token

    
    

    def get_openid(self, access_token):
    url = "https://graph.qq.com/oauth2.0/me?access_token=" + access_token
    try:
    response = urlopen(url)
    response_data = response.read().decode()
    data = json.loads(response_data[10:-4])
    openid = data.get("openid")
    except:
    logger.error('code=%s msg=%s' % (data.get('code'), data.get('msg')))
    raise QQErrorExcept
    return openid

    
    

    def get_qq_userinfo(self,access_token=None, openid=None):
    """根据access_token和openid获取用户信息"""
    params = {
    'access_token': access_token,
    'oauth_consumer_key': self.appid,
    'openid': openid,
    }
    url = 'https://graph.qq.com/user/get_user_info?' + urlencode(params)
    try:
    response = urlopen(url)
    response_data = response.read().decode()
    data = json.loads(response_data)
    return data
    except:
    logger.error('code=%s msg=%s' % (data.get('code'), data.get('msg')))
    raise QQErrorExcept

     

    2、再视图Views文件中调用:

    from django.shortcuts import render
    from rest_framework.views import  APIView
    from rest_framework.response import Response
    from rest_framework import status
    from urllib.request import urlopen
    from rest_framework_jwt.views import api_settings
    from .utils.oauthQQ import OauthQQ, QQErrorExcept
    from .models import OauthUser
    from users.models import User
    import random
    
    # Create your views here.
    
    class OauthQQAPIView(APIView):
        def get(self, request):
            state = request.query_params.get("state")
            oauth = OauthQQ(state=state)
            url = oauth.get_QQ_url()
            return Response({"url": url}, status=status.HTTP_200_OK)
    
    
    class OauthQQInfoAPIView(APIView):
        """根据前端获取到的code,后端获取access_token和用户信息"""
        def get(self, request):
            code = request.query_params.get("code")
            state = request.query_params.get("state")
            oauth = OauthQQ(state=state)
            try:
                access_token = oauth.get_QQ_access_token(code=code, state=state)
                openid = oauth.get_openid(access_token=access_token)
                qq_user_info = oauth.get_qq_userinfo(access_token=access_token, openid=openid)
    
            except QQErrorExcept:
                return Response({"message": "QQ登录异常,获取授权信息失败"}, status=status.HTTP_400_BAD_REQUEST)
    
            #根据获取到的openid去数据库查找是否有该用户
            try:
                oauth_user = OauthUser.objects.get(openid=openid)
                user = oauth_user.user
                # 用户存在,则返回jwt,登录成功
                jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
                jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
                payload = jwt_payload_handler(user)
                token = jwt_encode_handler(payload)
                user_info = {
                    "id": user.id,
                    "nickname": user.nickname,
                    "avatar": user.avatar.url,
                    "token": token,
                    "username": user.username
                }
                return Response({"user_info": user_info}, status=status.HTTP_200_OK)
            except OauthUser.DoesNotExist:
                # 如果QQ用户信息不存在,那么直接使用qq_nickname随机注册一个账号给用户
                nickname = qq_user_info.get("nickname")+"_"+str(random.randint(0000,9999))
                try:
                    user = User.objects.create_user(nickname=nickname, username=nickname)
                    oauth_user = OauthUser.objects.create(user=user, openid=openid)
                    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
                    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
                    payload = jwt_payload_handler(user)
                    token = jwt_encode_handler(payload)
                    user_info = {
                        "id": user.id,
                        "nickname": user.nickname,
                        "avatar": user.avatar.url,
                        "token": token,
                        "username": user.username
                    }
                except:
                    return  Response({"message": "创建用户失败"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                return Response({"user_info": user_info}, status=status.HTTP_200_OK)
    世间安得双全法,不负如来不负卿
  • 相关阅读:
    React Native学习(一)——搭建开发环境
    Linux 命令系列之 seq
    Linux 提高操作效率之 tab 命令补全
    Atlassian 系列软件安装(Crowd+JIRA+Confluence+Bitbucket+Bamboo)
    代码质量管理 SonarQube 系列之 安装
    kworkerds 挖矿木马简单分析及清理
    shell 脚本常用调试方法
    JVM 调优之 Eclipse 启动调优实战
    基于 Njmon + InfluxDB + Grafana 实现性能指标实时可视监控
    nmon 的下一代工具 njmon
  • 原文地址:https://www.cnblogs.com/shangguanruoling/p/12171525.html
Copyright © 2011-2022 走看看