1. 程式人生 > 其它 >美多商城專案(二)

美多商城專案(二)

QQ登入成功

  • 當前使用者成功完成QQ登入的動作以後,QQ伺服器會返回 code 和 'url回撥地址'
    回撥地址即 使用者登入完成以後,要跳轉的頁面

  • 前端要在該回調地址做的事情

    • 當該頁面載入完成以後,立即帶著 code向後端發起請求
      以便後端帶著code向騰訊伺服器獲取 access_token 和 openid

    • 對後端返回的資料進行判斷

      • 有包含使用者資訊,就儲存到本地

        • 依據後端提供的原網頁地址,跳轉回原頁面
      • 沒有包含使用者資訊,儲存後端加密過後的 openid

        • 展示登錄檔單,讓使用者填
### oauth_call.html
......
var vm = new Vue({
    el: '#app',
    data: {
        ......
    },
    mounted: function () {
        // 從路徑中獲取qq重定向返回的code
        var code = this.get_query_string('code');
        axios.get(this.host + '/oauth/qq/user/?code=' + code, {
            responseType: 'json',
        }).then(response => {
            if (response.data.user_id){
                // 使用者已繫結,儲存token
                sessionStorage.clear();
                localStorage.clear();
                localStorage.user_id = response.data.user_id;
                localStorage.username = response.data.username;
                localStorage.token = response.data.token;
                var state = this.get_query_string('state');
                location.href = state;
            }else{
                // 使用者未繫結,儲存openid並展示註冊頁面
                this.access_token = response.data.access_token;
                this.is_show_waiting = false;
            }
        }).catch(error => {
            console.log(error.response.data);
            alert('伺服器異常');
        })
    },
    methods: {
        // 獲取url路徑引數    
        get_query_string: function (name) {
            v......
        },
        // 生成uuid
        generate_uuid: function () {
            ......
        },
        check_pwd: function () {
            ......
        },
        check_phone: function () {
            ......
        },
        check_sms_code: function () {
            ......
        },
        // 傳送手機簡訊驗證碼
        send_sms_code: function () {
            .......
        },
        // 儲存
        on_submit: function () {
            ......
        }
});

後端新增介面,響應前端發過來code處理,要做的事情如下

- 獲取前端傳入的code

- 呼叫QQ登入SDK,向QQ伺服器發起兩次請求

    - 第一次帶著code獲取access_token
    - 第二次帶著access_token獲取openid


- 查詢db有沒有這個openid

    - 如果沒有,就建立一個新使用者與此openid繫結

    - 如果有,則程式碼登入成功,返回jwt狀態儲存資訊
class QQAuthUserView(APIView):
    def get(self,request,*args,**kwargs):

        code = request.query_params.get('code')
        if not code:
            return Response({'message':'缺少code'},status=status.HTTP_400_BAD_REQUEST)

        qq_auth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,client_secret=settings.QQ_CLIENT_SECRET,redirect_uri=settings.QQ_REDIRECT_URI)
        try:
            access_token = qq_auth.get_access_token(code)
            openid = qq_auth.get_open_id(access_token)
        except Exception as e: # 這裡要甩鍋騰訊,日誌記錄一下
            logger.info(e)
            return Response({'message':'qq伺服器錯誤'},status=status.HTTP_503_SERVICE_UNAVAILABLE)

        try:
            qq_user = QQAuthUser.objects.get(openid=openid)
        except QQAuthUser.DoesNotExist:
            # 這裡不可能再實現註冊請求,因為要發post請求,而我們寫在了get
            # return Response({'access_token':openid}) # 讓前端幫我們先臨時存著(要加密)
        else:
            # 手動簽發jwt,返回給前端使用者資訊
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
            payload = jwt_payload_handler(qq_user.user)
            token = jwt_encode_handler(payload)
            qq_user.user.token = token  # 把token加到user欄位

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

openid的加密處理

  • 引入 itsdangerous 庫,利用其時間加密類來完成需求
def generate_save_user_token(openid):
    # 生成加密序列化器(加鹽)
    serializer = Serializer(settings.SECRET_KEY,600)
    data = {'openid':openid}
    token = serializer.dumps(data) # bytes型別
    return token.decode() # 最終返回字串
  • 把之前的邏輯小改一下,加密openid後,再返回給前端
......
class QQAuthUserView(APIView):
    def get(self,request,*args,**kwargs):

        ......

        try:
            qq_user = QQAuthUser.objects.get(openid=openid)
        except QQAuthUser.DoesNotExist:
            # 加密處理,有效期10分鐘
            secret_openid = generate_save_user_token(openid)
            return Response({'access_token':secret_openid}) # 讓前端幫我們先臨時存著(要加密)
        ......