登錄接口設計和實現


---恢復內容開始---

1、用戶功能設計與設計:

  提供用戶注冊處理

  提供用戶登錄處理

  提供路由配置

2、用戶登錄接口設計:

  接受用戶通過POST 方法提交的登錄信息,提交的數據是JSON 格式數據。

  

  從user表中 email 找出匹配的一條記錄, 驗證密碼是否正確

  驗證通過說明是合法的用戶登錄,顯示歡迎頁面

  驗證失敗返回錯誤狀態碼,4XX

  整個過程都采用AJAX異步過程,用戶提交JSON 數據,服務端回去數據后處理,返回JSON  

  URL: /user/login

  METHOD:POST

3、路由配置:

    

4、登錄代碼:   

 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("輸入有誤")

 

  1、將用戶信息返回去,瀏覽器可以使用,處了密碼

    2、服務器端通過set_cookie 讓客戶端強行修改cookie(客戶端一般都開啟的cookie)

5、接口認證:

  如何獲取瀏覽器提交的token信息?

  1、使用Header中的Authorization  

    通過這個header增加token信息

    通過header發送數據,方法可以是post , get

  2、自定義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})

 

    

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

---恢復內容結束---

1、用戶功能設計與設計:

  提供用戶注冊處理

  提供用戶登錄處理

  提供路由配置

2、用戶登錄接口設計:

  接受用戶通過POST 方法提交的登錄信息,提交的數據是JSON 格式數據。

  

  從user表中 email 找出匹配的一條記錄, 驗證密碼是否正確

  驗證通過說明是合法的用戶登錄,顯示歡迎頁面

  驗證失敗返回錯誤狀態碼,4XX

  整個過程都采用AJAX異步過程,用戶提交JSON 數據,服務端回去數據后處理,返回JSON  

  URL: /user/login

  METHOD:POST

3、路由配置:

    

4、登錄代碼:   

 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("輸入有誤")

 

  1、將用戶信息返回去,瀏覽器可以使用,處了密碼

    2、服務器端通過set_cookie 讓客戶端強行修改cookie(客戶端一般都開啟的cookie)

5、接口認證:

  如何獲取瀏覽器提交的token信息?

  1、使用Header中的Authorization  

    通過這個header增加token信息

    通過header發送數據,方法可以是post , get

  2、自定義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的機制,且用戶信息自己建表管理,所以認證需要自己實現

6、中間件技術Midleware      

   官方定義:在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))

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

   

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM