美多商城專案(二)
阿新 • • 發佈:2022-12-09
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}) # 讓前端幫我們先臨時存著(要加密) ......