---恢復內容開始---數據庫
提供用戶註冊處理django
提供用戶登陸處理json
提供路由配置瀏覽器
接受用戶經過POST 方法提交的登陸信息,提交的數據是JSON 格式數據。服務器
從user表中 email 找出匹配的一條記錄, 驗證密碼是否正確cookie
驗證經過說明是合法的用戶登陸,顯示歡迎頁面session
驗證失敗返回錯誤狀態碼,4XXapp
整個過程都採用AJAX異步過程,用戶提交JSON 數據,服務端回去數據後處理,返回JSON 框架
URL: /user/login異步
METHOD:POST
1 # 登陸業務 2 def login(request:HttpRequest): 3 play = simplejson.loads(request.body) 4 try: 5 # 通常推薦先有索引的放前面 6 email = play['email'] 7 user = User.objects.filter(email=email).get() 8 9 # 輸入密碼 和 數據庫中密碼對比 10 if bcrypt.checkpw(play['password'].encode(), user.password.encode()): 11 # 驗證經過 12 token = gen_token(user.id) 13 res = JsonResponse({ 14 'user':{ 15 "user_id":user.id, 16 "name":user.name, 17 "email":user.email 18 }, 19 'token':token 20 }) 21 res.set_cookie('Jwt', token) # set cookie 22 return res 23 else: 24 return HttpResponseBadRequest(status=400) 25 except Exception as e: 26 return JsonResponse("輸入有誤")
二、服務器端經過set_cookie 讓客戶端強行修改cookie(客戶端通常都開啓的cookie)
如何獲取瀏覽器提交的token信息?
一、使用Header中的Authorization
經過這個header增長token信息
經過header發送數據,方法能夠是post , get
二、自定義header
JWT來發送token
咱們選擇第二種
認證:
基本上全部的業務都須要認證用戶的信息
在這裏比較時間戳,若是過時,就直接拋未認證401,客戶端收到後就該直接跳轉到登陸頁
若是沒有提交user id,就直接從新登陸,若是用戶查到了,填充user對象。
request -》 時間戳比較-》 user id 比較 --》向後執行。
測試: 沒有報錯,就證實是沒有修改過的
提供一個函數,調用業務函數以前,看下,以前是否登錄過
1 # 只要須要認證的地方均可以加這個功能,是否登錄過 2 def auth(view_func): 3 def wrapper(request:HttpRequest): 4 token = request.META.get('HTTP_JWT', None) 5 print(token,type(token),'== = = = = ') # str 6 try:# 獲取到 token中的payload,證實是以前登陸過的用戶 7 play = jwt.decode(token, KEY, algorithms=['HS256']) 8 print(play, type(play),'=============') 9 # 可是雖然是以前的,可是得確保,這一時刻,數據庫中還存在這個用戶嗎,是否激活狀態等 10 user = User.objects.get(pk=play["user_id"]) 11 print(user,'==== = = = = = = == ') 12 # 若是查到了,接下來的業務處理: 13 if user: 14 #查到,也就是已經登陸,要利用這些用戶信息,因此要動態註冊到request中 15 request.user = user # 這樣,下面執行show方法的時候,就能夠利用這個用戶屬性了 16 # 若是沒查到,user就報錯了,因此這塊不必寫 17 # else: 18 # return HttpResponseBadRequest() 19 except Exception as e: 20 print(e) 21 return HttpResponseBadRequest('n or p 錯誤') 22 ret = view_func(request) 23 # 這個中間還能夠執行去其餘的業務。。。。。 24 return ret 25 return wrapper 26 27 @auth -----裝飾器實現 28 def show(request:HttpRequest): 29 # 例如: 30 print(request.user,'==') 31 print(type(request.user)) 32 return JsonResponse({'1':7})
---恢復內容結束---
提供用戶註冊處理
提供用戶登陸處理
提供路由配置
接受用戶經過POST 方法提交的登陸信息,提交的數據是JSON 格式數據。
從user表中 email 找出匹配的一條記錄, 驗證密碼是否正確
驗證經過說明是合法的用戶登陸,顯示歡迎頁面
驗證失敗返回錯誤狀態碼,4XX
整個過程都採用AJAX異步過程,用戶提交JSON 數據,服務端回去數據後處理,返回JSON
URL: /user/login
METHOD:POST
1 # 登陸業務 2 def login(request:HttpRequest): 3 play = simplejson.loads(request.body) 4 try: 5 # 通常推薦先有索引的放前面 6 email = play['email'] 7 user = User.objects.filter(email=email).get() 8 9 # 輸入密碼 和 數據庫中密碼對比 10 if bcrypt.checkpw(play['password'].encode(), user.password.encode()): 11 # 驗證經過 12 token = gen_token(user.id) 13 res = JsonResponse({ 14 'user':{ 15 "user_id":user.id, 16 "name":user.name, 17 "email":user.email 18 }, 19 'token':token 20 }) 21 res.set_cookie('Jwt', token) # set cookie 22 return res 23 else: 24 return HttpResponseBadRequest(status=400) 25 except Exception as e: 26 return JsonResponse("輸入有誤")
二、服務器端經過set_cookie 讓客戶端強行修改cookie(客戶端通常都開啓的cookie)
如何獲取瀏覽器提交的token信息?
一、使用Header中的Authorization
經過這個header增長token信息
經過header發送數據,方法能夠是post , get
二、自定義header
JWT來發送token
咱們選擇第二種
認證:
基本上全部的業務都須要認證用戶的信息
在這裏比較時間戳,若是過時,就直接拋未認證401,客戶端收到後就該直接跳轉到登陸頁
若是沒有提交user id,就直接從新登陸,若是用戶查到了,填充user對象。
request -》 時間戳比較-》 user id 比較 --》向後執行。
測試: 沒有報錯,就證實是沒有修改過的
提供一個函數,調用業務函數以前,看下,以前是否登錄過
1 # 只要須要認證的地方均可以加這個功能,是否登錄過 2 def auth(view_func): 3 def wrapper(request:HttpRequest): 4 token = request.META.get('HTTP_JWT', None) 5 print(token,type(token),'== = = = = ') # str 6 try:# 獲取到 token中的payload,證實是以前登陸過的用戶 7 play = jwt.decode(token, KEY, algorithms=['HS256']) 8 print(play, type(play),'=============') 9 # 可是雖然是以前的,可是得確保,這一時刻,數據庫中還存在這個用戶嗎,是否激活狀態等 10 user = User.objects.get(pk=play["user_id"]) 11 print(user,'==== = = = = = = == ') 12 # 若是查到了,接下來的業務處理: 13 if user: 14 #查到,也就是已經登陸,要利用這些用戶信息,因此要動態註冊到request中 15 request.user = user # 這樣,下面執行show方法的時候,就能夠利用這個用戶屬性了 16 # 若是沒查到,user就報錯了,因此這塊不必寫 17 # else: 18 # return HttpResponseBadRequest() 19 except Exception as e: 20 print(e) 21 return HttpResponseBadRequest('n or p 錯誤') 22 ret = view_func(request) 23 # 這個中間還能夠執行去其餘的業務。。。。。 24 return ret 25 return wrapper 26 27 @auth -----裝飾器實現 28 def show(request:HttpRequest): 29 # 例如: 30 print(request.user,'==') 31 print(type(request.user)) 32 return JsonResponse({'1':7})
Django的認證:
本項目使用了無session的機制,且用戶信息本身建表管理,因此認證須要本身實現
官方定義:在Django的request 和response處理過程當中,由框架提供的hook鉤子
中間件技術,在1.10以後,發生改變,使用新的定義方式
參看:https://docs.djangoproject.com/en/1.11/topics/http/middleware/#writing-your-own-middleware
中間件實現方式:有兩種
自定義的中間件,也要在這裏註冊:通常寫在最後,先用框架本身的中間件。
本身寫中間件:https://docs.djangoproject.com/en/1.11/topics/http/middleware/#writing-your-own-middleware
右擊中間件名,選擇copyreference,添加到settings.py中。
可是,這樣全部的請求和響應都攔截,咱們還得判斷是否是訪問的想要攔截的view函數,因此,考慮其餘的方法。中間件有不少用途,適當的攔截全部請求和響應,例如瀏覽器端的IP 是否被禁用,UserAgent分析,異常響應的統一處理。
例如本項目的認證,登陸的時候,就不能用中間件,因此不適合註冊一箇中間件來攔截,而是使用裝飾器,須要攔截的就加上此功能。
裝飾器:
在須要認證 的view 函數上增長認證功能,寫一個裝飾器函數,誰須要認證,就在這個view函數上應用這個裝飾器
1 AUTH_EXPIRE = 8*60*60 # 8 小時過時,能夠卸載settings中,經過from django.conf import settings調用 2 # 只要須要認證的地方均可以加這個功能,是否登錄過 3 def auth(view_func): 4 def wrapper(request:HttpRequest): 5 token = request.META.get('HTTP_JWT', None) 6 print(token,type(token),'== = = = = ') # str 7 try:# 獲取到 token中的payload,證實是以前登陸過的用戶 8 play = jwt.decode(token, KEY, algorithms=['HS256']) 9 # 可是雖然是以前的,可是得確保,這一時刻,數據庫中還存在這個用戶嗎,是否激活狀態等 10 # 驗證過時時間: 11 current = datetime.datetime.now().timestamp() 12 if (current - play.get('timestamp', 0)) > AUTH_EXPIRE: 13 return HttpResponse("過時了") 14 15 user = User.objects.get(pk=play["user_id"]) 16 # 若是查到了,接下來的業務處理: 17 if user: 18 #查到,也就是已經登陸,要利用這些用戶信息,因此要動態註冊到request中 19 request.user = user # 這樣,下面執行show方法的時候,就能夠利用這個用戶屬性了 20 # 若是沒查到,user就報錯了,因此這塊不必寫 21 # else: 22 # return HttpResponseBadRequest() 23 except Exception as e: 24 print(e) 25 return HttpResponseBadRequest('n or p 錯誤') 26 ret = view_func(request) 27 # 這個中間還能夠執行去其餘的業務。。。。。 28 return ret 29 return wrapper 30 31 @auth # 很自由的應用在須要認證的view 函數上。 32 def show(request:HttpRequest): 33 # 例如: 34 print(request.user,'==') 35 print(type(request.user)) 36 return JsonResponse({'1':7})
Jwt 過時問題:(過時兩種方式:過時的起點時間 和 到期時間)
pyjwt 支持過時設定,在decode的時候,若是過時,則拋出異常,
須要在payload中增長 claim exp。exp要求是一個整數int的時間戳。
1 # 只要須要認證的地方均可以加這個功能,是否登錄過 2 def auth(view_func): 3 def wrapper(request:HttpRequest): 4 token = request.META.get('HTTP_JWT', None) 5 print(token,type(token),'== = = = = ') # str 6 try:# 獲取到 token中的payload,證實是以前登陸過的用戶 7 # 認證的同時,驗證過時時間:過時或拋異常(能夠經過時間判斷,塊過時的時候,續期,set cookie從新發一次) 8 play = jwt.decode(token, KEY, algorithms=['HS256']) 9 # 可是雖然是以前的,可是得確保,這一時刻,數據庫中還存在這個用戶嗎,是否激活狀態等 10 11 user = User.objects.get(pk=play["user_id"]) 12 # 若是查到了,接下來的業務處理: 13 if user: 14 #查到,也就是已經登陸,要利用這些用戶信息,因此要動態註冊到request中 15 request.user = user # 這樣,下面執行show方法的時候,就能夠利用這個用戶屬性了 16 # 若是沒查到,user就報錯了,因此這塊不必寫 17 # else: 18 # return HttpResponseBadRequest() 19 except Exception as e: 20 print(e) 21 return HttpResponseBadRequest('n or p 錯誤') 22 ret = view_func(request) 23 # 這個中間還能夠執行去其餘的業務。。。。。 24 return ret 25 return wrapper
測試用的:exp claim,此代碼,能夠用於續期,經過判斷,快過時,就經過set cookie從新發一個jwt 過去。
1 import jwt 2 import datetime 3 import threading 4 5 event = threading.Event() 6 key = 'jerry' 7 # 在jwt 的payload中增長 exp claim 8 data = jwt.encode({'name':'jerry','exp':int(datetime.datetime.now().timestamp() + 3)}, key) 9 print(jwt.get_unverified_header(data))# 獲取沒有過時的頭 10 try: 11 while not event.wait(1): 12 print(jwt.decode(data, key)) 13 print(datetime.datetime.now().timestamp()) 14 except jwt.ExpiredSignatureError as e:# 過時就拋異常 15 print(e) 16 17 print(jwt.get_unverified_header(data))