用戶登錄,把token放到數據庫中前端
import uuid import redis import datetime from rest_framework.views import APIView from rest_framework.response import Response from app02 import models from django.contrib import auth from app02.utils.myexception import MyErrorException # 點擊登錄,滑動驗證提交數據,返回True或者False from app02.utils.captcha_verify import verify redis_conn = redis.Redis(decode_responses=True) class Login(APIView): def post(self,request): # 獲取前端發過來的數據,驗證須要的三個數據是否成功,成功返回True status = verify(request.data) if not status: raise MyErrorException(1010,'滑動驗證失敗') # 200:成功 400:失敗 login_dic = {'code': None, 'username': None, 'msg': None, 'token': None} uname = request.data.get('username') upwd = request.data.get('password') # 直接驗證UserInfo表,且密碼是加密去進行驗證的,獲得的仍是用戶信息的對象 userinfo_obj = auth.authenticate(username=uname,password=upwd) if userinfo_obj: # 若是登錄過的用戶,再次登錄的話,數據庫中token值會變化, # 則redis裏面的token必須刪除掉,由於已經沒用了,用戶再用這個token訪問 # 就會告訴用戶認證失敗. try : if redis_conn.get(userinfo_obj.auth_token.key) : redis_conn.delete(userinfo_obj.auth_token.key) except Exception as e: pass # 設置一個隨機的字符串,用來賦值給token random_str = uuid.uuid4() #(1)添加數據到token表 models.Token.objects.update_or_create( # 驗證帳號密碼成功,就把token和時間(添加或更新)到表中 defaults={'key':random_str,'created':datetime.datetime.now()}, user = userinfo_obj ) login_dic['code'] = 200 login_dic['username'] = uname login_dic['msg'] = '登錄成功' login_dic['token'] = random_str return Response(login_dic) else : login_dic['code'] = 400 login_dic['msg'] = '登錄失敗' return Response(login_dic)
認證組件,數據庫中token過時時間14天,redis中存放的 token,用戶id(k,v) 過時時間爲7天python
import datetime import pytz import redis from app02 import models from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed # 設置一個redis緩存數據庫的內存 redis_conn = redis.Redis(decode_responses=True) # 認證組件 class My_Authentication(BaseAuthentication): def authenticate_header(self, request): pass def authenticate(self, request): # 請求的token放到了請求頭裏面 # 名字 Authentication:token ,請求頭裏面的內容都會被自動處理成HTTP_大寫的鍵 # token = request.META.get('HTTP_AUTHENTICATION') # 請求路徑?後面的值,GET.get拿取路徑(?token=...)的token值 token = request.query_params.get('token') # 來redis數據庫來取token爲鍵的值,若是存在,說明緩存中的token數據有效,認證成功 # 若是沒有值得話,代碼繼續向下執行 redis_user_id = redis_conn.get(token) if redis_user_id : print('redis緩存認證成功') # 返回這個request.user爲token對應的用戶信息的id, request.auth爲token值 return redis_user_id,token # 從數據庫中進行驗證,看是否能夠認證成功 token_obj = models.Token.objects.filter(key=token).first() if token_obj : # 把當前的時間進行轉換,由於數據庫存的時間是通過地區轉換的時間,轉換才能加減 now = datetime.datetime.now() now = now.replace(tzinfo=pytz.timezone('UTC')) # 建立或更新token時的時間 created_time = token_obj.created # 此次使用token,距離建立token表的時間有多久 right_time = now - created_time # 若是距離token表的時間超過了14天,則說明token表雖然存在,可是過時了. if right_time > datetime.timedelta(days=14): raise AuthenticationFailed('認證過時了') else : # 此次使用距離token值過時還有多少時間 # 這個時間是爲了避免讓redic過時時間超過數據庫的過時時間 lift_time = datetime.timedelta(days=14) + created_time - now # 把token做爲鍵,token對應的用戶信息id做爲值,添加到redis # token緩存在redis裏面是7天,在數據庫中是14天 redis_conn.set(token,token_obj.user.pk,min(lift_time.total_seconds(),7*24*3600)) print('數據庫token認證') # 返回這個request.user爲token對應的用戶信息的id,request.auth爲token值 return token_obj.user.pk,token #(若是數據庫token表中驗證路徑中token的值不存在} else: raise AuthenticationFailed('認證失敗')