QQ第三方登錄-python_web開發_django框架


准備工作

1. 成為QQ互聯的開發者 參考鏈接:

<http://wiki.connect.qq.com/%E6%88%90%E4%B8%BA%E5%BC%80%E5%8F%91%E8%80%85>

2. 審核通過后,創建應用,即獲取本項目對應與QQ互聯的應用ID 參考鏈接:http://wiki.connect.qq.com/__trashed-2

3. 在 models.py 中定義QQ身份(openid)與用戶模型類User的關聯關系

class OAuthQQUser(models.Model):
   """
  QQ登錄用戶數據
  """
   user = models.ForeignKey('users.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  # 單復數同名

4. QQ登錄SDK使用

初始化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)

實現流程

具體流程

  1. 返回QQ登錄網址的視圖

    1.1 在配置文件中添加關於QQ登錄的應用開發信息

    # QQ登錄參數
    QQ_CLIENT_ID = 'xxxx'  # ID
    QQ_CLIENT_SECRET = 'xxxxxxxxxxxx'  # 密鑰
    QQ_REDIRECT_URI = 'http://www.xxxx.xxx/oauth_callback.html'  # 回調域

    1.2 接口設計

    • 請求方式:GET /oauth/qq/statues/?state=xxx

    • 請求參數:查詢字符串參數

      參數名 類型 是否必須 說明
      state str 用戶QQ登錄成功后進入的網址
    • 返回數據:JSON

      {"login_url": oauth.get_qq_url()}
      返回值 類型 是否必須 說明
      login_url str qq登錄網址

    1.3 邏輯實現

    class QQAuthURLView(APIView):
       """
      提供QQ登錄頁面網址

      """
       def get(self, request):

           # state表示從哪個頁面進入到的登錄頁面,將來登錄成功后,就自動回到那個頁面
           state= request.query_params.get('state')
           if not state:
               state= '/'

           # 獲取QQ登錄頁面網址
           oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID, client_secret=settings.QQ_CLIENT_SECRET, redirect_uri=settings.QQ_REDIRECT_URI, state=state)
           login_url = oauth.get_qq_url()

           return Response({'login_url': login_url})
  1. OAuth認證

    准備oauth_callback回調頁,用於掃碼后接受Authorization Code

    通過Authorization Code獲取Access Token

    通過Access Token獲取OpenID

    2.1 接口設計

    • 請求方式:GET /oauth/qq/users/?code=xxx

    • 請求參數: 查詢字符串參數

      參數名 類型 是否必須 說明
      code str qq返回的授權憑證code
    • 返回數據

      {"access_token": xxxx,}

      {
         "token": "xxx",
         "username": "python",
         "user_id": 1
      }
      返回值 類型 是否必須 說明
      access_token str 用戶是第一次使用QQ登錄時返回,其中包含openid,用於綁定身份使用,注意這個是我們自己生成的
      token str 用戶不是第一次使用QQ登錄時返回,登錄成功的JWT token
      username str 用戶不是第一次使用QQ登錄時返回,用戶名
      user_id int 用戶不是第一次使用QQ登錄時返回,用戶id

    2.2 邏輯實現

    oauth/views.py

    class QQAuthUserView(GenericAPIView):
       """用戶掃碼登錄的回調處理"""

       # 指定序列化器
       serializer_class = serializers.QQAuthUserSerializer

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

           # 創建工具對象
           oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                           client_secret=settings.QQ_CLIENT_SECRET,
                           redirect_uri=settings.QQ_REDIRECT_URI)

           try:
               access_token = oauth.get_access_token(code)

               # 3,通過access_token獲取openid
               openid = oauth.get_open_id(access_token)

               # 4,通過openid查詢oauthqq對象

               try:
                   oauth_qq_user = OAuthQQUser.objects.get(openid=openid)
               except OAuthQQUser.DoesNotExist:
                   # ①, 沒有項目用戶, 也沒有OAuthQQUser用戶
                   # ②, 有項目用戶, 沒有OAuthQQUser用戶

                   # 5,qq用戶沒有和項目用戶綁定過,加密openid,並返回
                   access_token_openid = generate_save_user_openid(openid)
                   return Response({"access_token": access_token_openid})

           except Exception:
               return Response({"message": "請求qq服務器異常"},
                               status=status.HTTP_400_BAD_REQUEST)

           # 6,oauth_qq_user存在,並且綁定過了美多用戶
           user = oauth_qq_user.user

           # 7,組織數據,拼接token,返回響應
           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)

           return Response({
               "user_id": user.id,
               "username": user.username,
               "token": token
          })

    oauth/utils.py** 中准備序列化 OpenID 的工具方法**

    # 對openid加密
    def generate_save_user_openid(openid):
       #1,創建TJWSSerializer對象
       serializer = TJWSSerializer(settings.SECRET_KEY,expires_in=300)

       #2,加密數據
       token = serializer.dumps({"openid":openid})

       #3,返回
       return token
  1. OpenID綁定用戶

如果用戶是首次使用QQ登錄,則需要綁定用戶


3.1 接口設計

  • 請求方式:POST /oauth/qq/users/

  • 請求參數:JSON 或 表單

    參數名 類型 是否必須 說明
    mobile str 手機號
    password str 密碼
    sms_code str 短信驗證碼
    access_token str 憑據(包含openid)
  • 返回數據:JSON

    返回值 類型 是否必須 說明
    token str JWT token
    id int 用戶id
    username str 用戶名

3.2 邏輯實現

  • oauth/views.py

    def post(self, request):
           # 1,獲取數據
           dict_data = request.data

           # 2,獲取序列化器,校驗數據
           serializer = self.get_serializer(data=dict_data)
           serializer.is_valid(raise_exception=True)

           # 3,數據入庫
           oauth_qq = serializer.save()

           # 4,組織,數據返回響應
           user = oauth_qq.user
           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)

           return Response({
               "user_id": user.id,
               "username": user.username,
               "token": token
          })
  • 新建 oauth/serializers.py 文件

  • from rest_framework import serializers
    from .utils import check_save_user_openid
    from django_redis import get_redis_connection
    from users.models import User
    from .models import OAuthQQUser
    class QQAuthUserSerializer(serializers.Serializer):
       mobile = serializers.RegexField(label="手機號",regex=r"1[3-9]\d{9}")
       password = serializers.CharField(label="密碼",min_length=8,max_length=20)
       sms_code = serializers.CharField(label="短信",min_length=6,max_length=6)
       access_token = serializers.CharField(label="token",min_length=1)

       def validate(self, attrs):
           """多字段校驗"""
           #1,獲取加密的openid
           access_token = attrs["access_token"]

           #2,調用方法解密openid,判斷是否存在
           openid = check_save_user_openid(access_token)

           if not openid:
               raise serializers.ValidationError("openid失效")

           #3,獲取redis中的短信,判斷為空,正確性
           sms_code = attrs["sms_code"]
           mobile = attrs["mobile"]
           redis_conn = get_redis_connection("code")
           redis_sms_code = redis_conn.get("sms_%s"%mobile)

           if not redis_sms_code:
               raise serializers.ValidationError("短信驗證碼過期")

           if sms_code != redis_sms_code.decode():
               raise serializers.ValidationError("短信驗證碼錯誤")

           #4,通過手機號查詢美多用戶是否存在,判斷密碼正確性
           user = None
           try:
               user = User.objects.get(mobile=mobile)
           except User.DoesNotExist:
               pass
           else:
               #5,表示用戶存在,判斷密碼正確性
               if not user.check_password(attrs["password"]):
                   raise serializers.ValidationError("密碼錯誤")

           #6,返回校驗之后的內容
           attrs["openid"] = openid
           attrs["user"] = user
           return attrs

       #重寫create方法,創建qq用戶
       def create(self, validated_data):
           """validated_data,就上面返回的attrs"""
           #1,創建qq用戶
           oauth_qq = OAuthQQUser()

           #2,判斷用戶是否存在,如果存在設置屬性,如果不存在直接創建
           user = validated_data["user"]
           if not user:
               user = User.objects.create(
                   username=validated_data["mobile"],
                   mobile=validated_data["mobile"],
              )
               user.set_password(validated_data["password"])
               user.save()

           #3,設置qq用戶屬性
           oauth_qq.openid = validated_data["openid"]
           oauth_qq.user = user
           oauth_qq.save()

           #4,返回
           return oauth_qq
  • oauth/utils.py 中准備序列化 OpenID 的工具方法

    # 對openid解密
    def check_save_user_openid(access_token):
       #1,創建serializer對象
       serializer = TJWSSerializer(settings.SECRET_KEY,expires_in=300)

       #2,解密openid
       dict_data = serializer.loads(access_token)

       #3,返回
       return dict_data.get("openid")

    以上引用:https://www.jianshu.com/p/8d46ff12baf7


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM