三方登入原理及後端示例程式碼

God_Hearing發表於2020-10-11

原理圖

微博示例:

在這裡插入圖片描述

注意,此時後端有三個介面,分別為,獲取掃碼url的介面,驗證是否為繫結使用者的介面,繫結介面

  • 注意,驗證是否為繫結使用者的介面並沒有繫結介面的功能
    1.1 前端獲取認證code
    1.在Vue頁面載入時 動態傳送請求獲取微博授權url
    2.django收到請求的url後,通過微博 應用ID(client_id)和回撥地址(redirect_uri) 動態 生成授 權url返回給Vue
    3.當使用者點選上面的url進行掃碼,授權成功會 跳轉我們的回撥介面並附加code引數
    4.Vue獲取到微博返回的code後,會 將code傳送給django後端 (上面的redirect_uri)
    1.2 獲取微博access_token
    後端獲取code後,結合client_id、client_secret、redirect_uri引數進行傳遞,獲取微博 access_token
    1.3 獲取微博使用者基本資訊並儲存到資料庫
    使用獲得的access_token呼叫獲取使用者基本資訊的介面, 獲取使用者第三方平臺的基本資訊
    使用者基本資訊 儲存到資料庫,然後關聯本地使用者 ,然後將使用者資訊返回給前端
    1.4 生成token給Vue
    django後端藉助微博認證成功後,可以 使用JWT生成token ,返回給Vue
    Vue將token儲存到localStorage中 ,以便使用者訪問其他頁面進行身份驗證
    2.第三方登入與本地登入的關聯(三種情況)
    2.1 情況1: 本地未登入,第一次登入第三方
    此時相當於註冊,直接把第三方資訊拉取來並註冊成本地使用者就可以了,並建立本地使用者與第三方使用者(openid)的繫結關係

2.2 情況2**:本地未登入,再次登入第三方**
此時使用者已註冊,獲取到openid後直接找出對應的本地使用者即可

2.3 情況3**:本地登入,並繫結第三方**
這個只要將獲取到的openid繫結到本地使用者就可以了

3.oauth認證原理
OAuth是一個開放標準,允許使用者讓第三方應用訪問該使用者在某一網站上儲存的私密的資源,而無需將使用者名稱和密碼提供給第三方應用。
OAuth允許使用者提供一個令牌,而不是使用者名稱和密碼來訪問他們存放在特定服務提供者的資料。
這個code如果能出三方換取到資料就證明這個使用者是三方真實的使用者
4.為什麼使用三方登入
服務方希望使用者註冊, 而使用者懶得填註冊時的各種資訊(主要是為了保證使用者的唯一性,各種使用者名稱已佔用,密碼格式限制).
而像微信, QQ, 微博等幾乎每個人都會安裝的應用中使用者肯定會在其中某一個應用中已經註冊過,證明該使用者在已經註冊的應用中的唯一性.
第三方登入的實質就是在授權時獲得第三方應用提供的代表了使用者在第三方應用中的唯一性的openid.並將openid儲存在第三方服務控制的本地儲存.
就是在授權時獲得第三方應用提供的代表了使用者在第三方應用中的唯一性的openid.並將openid儲存在第三方服務控制的本地儲存.


註冊微博

地址:https://open.weibo.com/
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述


回撥頁面是指掃碼後,攜帶code碼返回給前端的url地址,在後端的獲取掃碼url介面中和微博後臺中一致

使用微博使用者code+微博開發者賬號資訊換取微博的認證access_token

獲取url介面程式碼

class WeiboUrl(APIView):
    # 自定義許可權類
    permission_classes = (AllowAny,)

    def post(self, request):
        url = 'https://api.weibo.com/oauth2/authorize?'
        data = {
            'client_id':'1006916973',
            'response_type':'code',
            'redirect_uri':'http://127.0.0.1:8888/oauth/callback',
        }
        weibo_url = url + urlencode(data)
        return Response({'code':'0','msg':'成功','data':{'url':weibo_url}})


回撥介面

class OauthWeiboCallback(APIView):
    # 自定義許可權類
    permission_classes = (AllowAny,)

    def post(self, request):
        # 接收vue端傳過來的code(微博的使用者code)
        # 1.使用微博使用者code+微博開發者賬號資訊換取微博的認證access_token
        code = request.data.get('code')
        data = {
            'client_id':'1006916973',
            'client_secret':'b089ebeb447f4def683ef737c2ed762c',
            'grant_type':'authorization_code',
            'code':code,
            'redirect_uri':'http://127.0.0.1:8888/oauth/callback',
        }
        url = 'https://api.weibo.com/oauth2/access_token'
        data = requests.post(url=url, data=data).json()
        access_token = data.get('uid')
        weibo_uid = data.get('access_token')
        # 2. 根據uid 查詢繫結情況
        try:
            oauth_user = OauthUser.objects.get(uid=weibo_uid, oauth_type='1')
        except Exception as e:
            oauth_user =None
        # 返回動作, 登陸成功/需要繫結使用者 type=0 登陸成功, 1,授權成功,需要繫結
        if oauth_user:
            # 4. 如果繫結了,返回token, 登入成功
            user = oauth_user.user
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            # jwt_response_payload_handler為user模組定義的jwt返回的資訊
            data = jwt_response_payload_handler(token, user)
            data['type'] = '0'  # 指定為登陸成功
            return Response({'code':0, 'msg':'登入成功', 'data':data})
        else:
            # 5.如果沒繫結,返回標誌,讓前端跳轉到繫結頁面
            return Response({'code':0, 'msg':'授權成功', 'data':{'type':'1', 'uid':weibo_uid}})

繫結介面

class OauthWeiboBindUser(APIView):
    permission_classes = (AllowAny,)

    def post(self,request):
        # 繫結使用者, 1.已註冊使用者, 2.未註冊使用者
        # 1.1 獲取使用者名稱, 密碼,weibo_uid
        username = request.data.get('username')
        password = request.data.get('password')
        weibo_uid = request.data.get('weibo_uid')
        if not all([username,password,weibo_uid]):
            return Response({'code':999, 'msg':'引數不全'})
        # 0.判斷是否存在此使用者
        try:
            user = User.objects.get(username=username)
        except Exception as e:
            user = None
        # 1.已註冊使用者
        if user:
            #1.2 如果存在就驗證密碼,驗證通過,就繫結,返回token,登陸成功
            if user.check_password(password):
                ou = OauthUser(uid=weibo_uid,user=user,oauth_type='1')
                ou.save()
                payload = jwt_payload_handler(user) # 通過user物件獲取到jwt的payload資訊
                token = jwt_encode_handler(payload)     # 生成token
                data = jwt_response_payload_handler(token, user)
                data['type'] = '0'  # 指定為登陸成功
                return Response({'code':0,'msg':'登陸成功','data':data})
            else:
                return Response({'code':999, 'msg':'密碼錯誤'})
        else:
            # 2. 未註冊使用者
            # 2.1 生成新使用者,設定使用者名稱密碼,儲存,然後繫結,返回token,登陸成功
            user = User(username=username)
            user.set_password(password)
            user.save()
            ou = OauthUser(uid=weibo_uid,user=user, oauth_type='1')
            ou.save()
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            data = jwt_response_payload_handler(token, user)
            data['type'] = '0'  # 指定為登陸成功
            return Response({'code':0, 'msg':'登陸成功','data':data})

yload_handler(token, user)
data[‘type’] = ‘0’ # 指定為登陸成功
return Response({‘code’:0, ‘msg’:‘登陸成功’,‘data’:data})


相關文章