您好,登錄后才能下訂單哦!
本篇內容介紹了“Django中session登錄驗證操作方法是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
cookie 和 session 的基本概念這里不做贅述,這里簡單講一下在 Django 中如何使用自定義的模塊來實現登錄、登出以及僅允許登錄用戶訪問某些接口的操作。
Django 有一套自帶的 auth 驗證模塊,包括用戶以及用戶及相應的權限的表和操作,我們這里沒有用,而是單獨自定義一個 user 模塊以及相應的功能函數用來實現用戶的注冊、登錄和登出功能。
session 在這里的使用流程大致如下:
1、通過 login 接口,驗證成功后,將某些信息寫入 session,可以是 user_id,或者是某個你自定義的特定的字段,反正是后續需要進行驗證是否登錄成功的數據
2、在訪問特定的、需要登錄才可查看的接口前,先檢查前端返回的數據中是否包含我們在上一步中寫入的數據來確保用戶是處于登錄狀態,如果是,則允許繼續訪問,否則返回未登錄的信息,提示用戶需要先進行登錄操作
3、通過 logout 接口,將用戶在 login 接口里寫入的登錄信息抹除,返回登出成功信息
在 Django 中,系統自動為我們準備好了 session 的所有相關的操作,我們只需要在后續的登錄操作中往里面寫入我們需要驗證的數據即可。
Django 這部分為我們準備好的 session 操作也是通過中間件的形式存在的,是 settings.py 的 MIDDLEWARE 的 'django.contrib.sessions.middleware.SessionMiddleware'
如果不指定其他存儲方式,session 的數據默認存在于我們的后端表中,這個我們在第一次執行 migrate 的時候已經自動為我們創建了該表,名為 django_session
。
表數據的操作和查看我們在后面再詳細介紹。
前面已經介紹了 session 的操作流程,這里我們介紹一下 session 的相關配置和方法。
以下設置都在 settings.py 中設置,事實上,這些 session 的默認配置就差不多可以使用,后續有特殊需求我們可以再來查看,這里只介紹幾個我覺得方便我們使用的。
SESSION_COOKIE_AGE
session 過期時間,默認為 1209600,即 14 * 24 * 60 * 60,為 14天。
我們可以在 settings.py 中配置 session 的過期時長,也可以在程序中使用方法手動配置過期時長,方法的使用我們后面再介紹。
SESSION_COOKIE_NAME
默認值為 sessionid,在用戶登錄之后,請求我們系統,請求的 cookie 里會帶上 session key-value 的參數,這個 key 就是我們這里的 SESSION_COOKIE_NAME,默認為 sessionid。
如果想改成其他的名稱直接定義即可。
SESSION_ENGING
Django 存儲 session 具體數據的地方,默認值為 django.contrib.sessions.backends.db
,表示存在于數據庫,也就是我們前面說的在 django_session 這張表。
也可以存儲在文件或者緩存里。
這里接著介紹一下 session 相關的方法,這些方法的調用一般是在接口里通過 request.session 來操作。
這里我們只是做一下方法的作用和效果的介紹,具體用途我們在之后的示例中再詳細說明。
dict 操作
我們可以將 request.session 視作一個 dict,往里面添加 user_id,is_login 等用于標識用戶是否登錄的信息的時候可以直接操作,比如:
request.session["user_id"] = 1 request.session["is_login"] = True
keys()
輸出 request.session.keys() 返回的就是我們在前面往 session 里添加的數據。
同理,request.session.items() 輸出的也是我們往里添加的數據的 key-value 的值。
del 操作
當我們使用登出操作時,可以直接使用:
del request.session["user_id"]
這種方式會刪除 session 中我們保存的 user_id 信息,這樣用戶在訪問我們的接口的時候,如果我們做登錄驗證的操作,就會找不到已經登錄的信息。
之前我們說過,我們的 session 數據會保存在數據庫里,這種方式僅僅是刪除 session 中某個特定的 key-value,并不會刪除 django_session 表中這條數據
而如果想要直接刪除這一條 session 數據,則可以使用 flush() 方法
flush()
下面的操作則會直接操作數據庫刪除這條 session 數據:
request.session.flush()
flush() 和 前面的 del 方法都可以用作我們 logout 過程中的操作。
get_expiry_age()
獲取 session 過期秒數,這個值就是前面我們在 settings.py 中設置的 SESSION_COOKIE_AGE 的值。
clear_expired()
從 django_session 中移除過期的會話,下面會介紹 Session 這個 model 的相關操作,這里提前說一下這個函數。
django_session 會有一個 expire_date 字段,clear_expired() 這個操作就會刪除表里 expire_date 小于當前時間的數據。
前面介紹了 session 的相關配置和方法以及 session 的基本使用流程。接下來我們將介紹如何在系統中使用上 session。
在介紹 session 使用前,我們自定義一個 users application 來做一下相關準備。
新建一個 application 和 相關的配置,在前面的筆記中都有介紹,這里不再做贅述,比如 app 的創建、在 settings.py 里 INSTALLED_APPS 里的定義,和 hunter/urls.py 的 patterns 里新建一條數據,指向 users/urls.py 等操作。
其中,在 hunter/urls.py 中對 users app 的 url 前綴我們定義為 users,如下:
# hunter/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('blog/', include('blog.urls')), path('users/', include('users.urls')), ]
我們這里在 users/models.py 下新建一個 User model,然后對其進行相關的 migration 操作,使其表添加到數據庫中。
# users/models.py from django.db import models class User(models.Model): username = models.CharField(max_length=20, verbose_name="登錄用戶名", unique=True) password = models.CharField(max_length=256, verbose_name="加密密碼")
接下來,我們將新建幾個接口:
用戶注冊接口
用戶登錄接口
用戶注銷接口
用戶信息接口
可以先看下這幾個接口的代碼總攬,接著我們詳細介紹一下接口的操作。
users/urls.py from django.urls import path from users.views import LoginView, RegisterView, LogoutView, UserInfoView urlpatterns = [ path("register", RegisterView.as_view()), path("login", LoginView.as_view()), path("logout", LogoutView.as_view()), path("user/info", UserInfoView.as_view()), ]
users/views.py from django.contrib.auth.hashers import make_password, check_password from django.http import JsonResponse from django.views import View from users.models import User import json # 用戶注冊 class RegisterView(View): def post(self, request): request_json = json.loads(request.body) username = request_json.get("username") password = request_json.get("password") if not username or not password: result = {"code": -1, "msg": "username or password not valid"} else: if User.objects.filter(username=username).exists(): result = {"code": -1, "msg": "username exists"} else: User.objects.create(username=username, password=make_password(password)) result = {"code": 0, "msg": "success"} return JsonResponse(result, safe=False) # 用戶登錄 class LoginView(View): def post(self, request): request_json = json.loads(request.body) username = request_json.get("username") password = request_json.get("password") if not username or not password: result = {"code": -1, "msg": "login info error"} else: user = User.objects.filter(username=username).first() if not user: result = {"code": -1, "msg": "username not found"} else: if check_password(password, user.password): result = {"code": 0, "msg": "success"} request.session["username"] = username else: result = {"code": -1, "msg": "password error"} return JsonResponse(result, safe=False) # 用戶登出 class LogoutView(View): def post(self, request): if request.session.get("username"): del request.session["username"] # request.session.flush() return JsonResponse({"code": 0, "msg": "登出成功"}) # 用戶信息 class UserInfoView(View): def post(self, request): username = request.session.get("username") if username: result = {"code": 0, "msg": f"登錄用戶為{username}"} status = 200 else: result = {"code": -1, "msg": "用戶未登錄"} status = 401 return JsonResponse(result, status=status)
首先介紹一下,所有請求的參數都是放在 body 里以 json 格式傳遞,我這里都是通過 postman 來請求測試的。
其次,在請求里,session 的處理可以直接通過 request.session 的方式進行,以下見示例。
在注冊接口里,這里做了參數校驗的簡化,直接 json.loads() 處理 body 的內容,然后通過 Django 自帶的加密函數 make_password 將密碼以加密的形式保存。
登錄接口里,首先是校驗賬號密碼是否正確,判斷正確后我們將登錄用戶的 username 字段寫入 session,然后在用戶下一次請求的時候就會自動獲取該 session。
或者更正確的來說,用戶登錄在操作 request.session 之后,在返回 response 的時候,系統會在 django_session 里新增或者更新該用戶的記錄,這條數據有包含 session_key,session_data 和 expire_date 這幾個字段。
session_key,在 cookie 的名稱是 sessionid,postman 中第一次登錄之后,在之后的每一次接口請求都會將sessionid=xx 傳給后端,后端就會根據這個 session_key 的值去 django_session 表里查詢相應的記錄
如果這個 session_key 在表里不存在記錄,或者 expire_date 過期了,那么后端系統會自動給其值賦為 None,即認定此次接口請求是未登錄狀態。
expire_date 字段則是一個時間字段,主要用于判斷數據是否過期。
session_data 則是會包含我們寫入的數據,比如我們在用戶登錄的時候,通過 request.session["username"] = username
的方式寫入了一些特殊的標識,然后將其編碼成 session_data 的值存入數據庫,那么用戶在下次請求接口的時候我們就可以通過解碼 session_data,將值取出來用于判斷用戶是否登錄。
將 session_data 解碼的方式可以單獨通過獲取 django_session 的記錄然后獲取,但是在請求中,Django 為我么做了這些解碼工作,我們可以直接通過前面介紹的 request.session.items()
的方式來查看在當前登錄的 session_data 里寫入的 key-value 數據。
注意: 前后端并不直接將 session_data 作為值傳遞,而是會傳遞 session_key 這個參數,一些校驗的數據也都是放在 session_key 對應記錄的 session_data 中存在后臺的數據庫中。
我們假定獲取用戶信息接口要求用戶必須處于登錄狀態,實際上也是,因為用戶不登錄無法定位到用戶,然后獲取用戶的信息。
那么我們在進行下一步的實際操作前,我們肯定需要嘗試從 session 中獲取用戶相應的信息,如果獲取到了,則判斷是處于登錄狀態,否則是處于未登錄狀態,無法獲取用戶信息。
所以我們這里的判斷是從 session 中獲取 username 字段,通過判斷 username 是否有值來判斷用戶是否處于登錄狀態。
用戶注銷,也就是登出接口,我們這里用的是 del 的方式,這個主要是看我們驗證用戶登錄的方式,比如我們是通過向 session 中取值 username 來判斷用戶是否登錄,那么 del request.session["username"]
的操作即可實現注銷的功能。
注意: 這里執行的 del 操作僅僅是刪除 session_data 中的 {"username": "xxx"} 的數據,這條 session_key 對應的數據還存在。
可以看到,在這條代碼的下一行還有一條是執行的 flush() 操作,這個操作是直接在數據庫里刪除這條 session 記錄,這是一種更為徹底的登出操作。
這里還需要注意的一點是,del 操作的前提是 session 數據里必須要有 username 這個 key,否則會引起報錯,所以我們這里用了一個 if 判斷邏輯,我們還可以使用 try-except 操作,或者更為徹底的操作是直接使用 flush() 操作。
至此,用戶登錄登出以及 session 數據的基本使用操作就介紹完畢了,下面我們額外介紹一些操作。
django_session 表的單獨獲取查看操作一般在程序里不會出現,因為前后端都是通過 cookie 中 sessionid 直接獲取到對應的數據,但為了以防萬一,或者你對這張表有一些興趣,這里額外介紹一下如何單獨操作這張表里的數據。
django_session 表的引入方式如下:
from django.contrib.sessions.models import Session
然后通過 session_key 來獲取這條數據,比如 session_key 為 nqu3s71e38279bl5cbgju6sut64tnqmx
,就可以:
session_key = "nqu3s71e38279bl5cbgju6sut64tnqmx" session = Session.objects.get(pk=session_key) # session = Session.objects.get(session_key=session_key)
其中,我們向 session 里寫入的數據都包含在 session.session_data 里,我么可以直接通過 get_decoded() 方法來獲取:
session.get_decoded() # {'username': 'root'}
獲取用戶信息這個接口需要用戶登錄才可以接著獲取用戶信息,我們這里的操作是直接判斷 session 里是否含有 username 字段。
但是如果我們系統里大部分接口都是需要用戶先登錄才可訪問,這樣在每個 views 里都要先加這個判斷的操作,這樣的顯然是不實際的。
那么我們可以怎么操作來實現這個重復性的操作呢?
這里提供兩個方式,一個是裝飾器,一個是寫在中間件里。
其實如果直接使用 Django 自帶的登錄驗證的功能,是可以直接使用系統自帶的裝飾器的,但是我們這里的表都是手動操作的,所以這個功能的裝飾器我這里就自己實現了一個,相關代碼如下:
def login_required_manual(func): def wrapper(*args, **kwargs): request = args[1] if not request.session.get("username"): return JsonResponse({"code": -1, "msg": "not login"}, status=401) return func(*args, **kwargs) return wrapper class UserInfoView(View): @login_required_manual def post(self, request): username = request.session.get("username") return JsonResponse({"code": 0, "msg": f"登錄用戶{username}"})
可以看到,使用了登錄驗證的裝飾器之后,我們的代碼都簡潔了很多。
我們可以嘗試在調用登出接口后,再調用用戶信息接口,可以看到系統就自動返回了未登錄的信息了。
這里我們假定目前僅僅是注冊和登錄不需要登錄即可訪問,然后我們創建一個中間件如下:
# hunter/middlewares/auth_middleware.py from django.http import JsonResponse class AuthMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): path = request.path # url 路徑為 /users/register 和 /users/login 的接口不需要進行判斷驗證 if path not in [ "/users/register", "/users/login", ]: session = request.session if not session.get("username"): return JsonResponse({"code": -1, "msg": "not login"}, status=401) response = self.get_response(request) return response
然后在 hunter/settings.py 里加上這個中間件:
# hunter/settings.py INSTALLED_APPS = [ ... 'hunter.middlewares.auth_middleware.AuthMiddleware', ... ]
這樣,在每個接口請求到達 views 視圖前,都會經歷這個驗證的中間件,這里將接口路徑的判斷簡化成注冊接口和登錄接口,這兩個接口不需要登錄即可訪問,其他接口都設置成需要登錄才可訪問。
相比于裝飾器的做法,這里更推薦中間件的操作方式,這樣首先就不用在每個 views 前加上裝飾器,另外,需要登錄才可訪問的接口都可以在中間件部分統一列舉出來,方便查看。
“Django中session登錄驗證操作方法是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。