1. 程式人生 > >登入介面設計和實現

登入介面設計和實現

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

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))