cookie和session的使用
# 概念:cookie 是客戶端瀏覽器上的鍵值對
# 目的:為了做會話保持
# 來源:服務端寫入的,服務端再返回的響應頭中寫入,瀏覽器會自動取出來????????????????存起來是以key value 形式,有過期時間、path、http only等等
# 使用:只要瀏覽器中有cookie,再次向當前域發送請求,都會自動攜帶在請求頭中
? ? ? ? cookie:"name=lqz;age=19"
# 不安全問題---》cookie中發了敏感數據---》客戶能看到obj.set_cookie() # cookie設置 request.COOKIES.get() # cookie取值 ? request.COOKIES.clear() # 清空 ? ? ? ?
# 我們需要讓cookie變的安全---》敏感數據不在cookie中方法,而放在session中
?? ?-session是服務端的鍵值對
? ? -session跟cookie有什么關系呢?把key,以cookie的形式,存到瀏覽器中
? ? ?? ?{111:{name:lqz,age:19,password:123},222:{name:zs,age:19,password:666}}
? ??????sessionid:111
# 當前瀏覽器以后再發請就會攜帶過來
? ? -我們根據帶過來的cookie 111----》 從 session中取出對應的數據
# session的使用:?????????必須要先遷移表, session存在服務端的, 默認情況下存在, django-session表中
配置文件:SESSION_ENGINE = 'django.contrib.sessions.backends.db' # django項目有兩套配置文件:內置一套,項目自己一套
# django-session表的字段:
????????session_key: ? ? ?sessionid:隨機字符串
????????session_data:? 真正的數據(加密了)
????????expire_date: ? ? 過期時間request.session.get() # 取值 request.session['name']='lqz' # 賦值
# session的本質執行原理:
1 咱么寫了request.session['name']='lqz',本質就是向session 對象中放入了name=lqz
2 當前視圖函數結束---->經過 【中間件】------>返回給了前端
? ? ? ?django 內置了一個session中間件
? ? ? ?判斷:request.session 有沒有變化,如果有變化
# 情況一:django-session表中沒有數據
在表中創建出一條數據,隨機生成一個字符串[隨機字符串session_key],把數據存入django-session表
? ? ? ? ? ?session_key:adsfasd
? ? ? ? ? ?session_data: name=lqz ?加密后存到里面
? ? ? ? ? ??sessionid:adsfasd? ?把隨機字符串寫入到cookie中
# 情況二:django-session表中有數據
把session中所有的值加密后, 更新到django-session表的session_data中,其他不變? ? ? ?
3 下次 再發請求進入任意視圖函數---》又會經過【中間件】---》視圖函數
? ? ? ? 視圖函數中取session:request.session.get('age')
? ? ? ? 瀏覽器發請求(攜帶cookie過來)---》到了中間件---》根據sessionid取出隨機字符串
? ? ? ? 拿著隨機字符串去django-session中查【session_key】---》 能查到就把 session_data的數據解密---》放到request.session中????????無則添加,有則更新,請求來,取出隨機字符串對比,正確則解密
? ? ? ? 后續視圖函數中,才能取出值session的中間件把上述內容完成了:
procee_request ? process_response django.contrib.sessions.middleware.SessionMiddleware
# 配置session 存放路徑(未完成,需要你完成)
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' SESSION_ENGINE = 'django.contrib.sessions.backends.file' SESSION_FILE_PATH='c://xxx/x' SESSION_COOKIE_NAME = 'xxx' from django.conf import settings from django.contrib.sessions.backends import?
中間件
# 概念:中間件是介于request與response處理之間的一道處理過程,能在全局上改變django的輸入與輸出。因為改變的是全局,所以需要謹慎實用,用不好會影響到性能
# 作用:
?? ?1 全局的請求攔截---》如果它沒有登錄---》就不允許訪問
? ? 2 攔截所有請求,獲取請求的ip地址
? ? 3 記錄所有用戶的訪問日志
? ? 4 統一在響應頭中加數據? ??
# 代碼上:就是一個類,類中有幾個方法MIDDLEWARE = ['django.middleware.security.SecurityMiddleware',# session相關的中間件'django.contrib.sessions.middleware.SessionMiddleware',# 公共中間件---》訪問不帶 / 路徑,如果有 帶 / 的路徑,他會讓你重定向到這個地址'django.middleware.common.CommonMiddleware',# csrf認證 ? ?xss ?cors'django.middleware.csrf.CsrfViewMiddleware',# 認證:request.user--->這個中間件做的'django.contrib.auth.middleware.AuthenticationMiddleware',# django的消息框架---》flask--》閃現'django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware', ]
# 自定義中間件來使用,記錄用戶的請求地址和user-agent
class SaveRemoteAddr(MiddlewareMixin):def process_request(self, request):# request 是WSGIRequest 的對象# print(request.session) # 一定要保證,session的中間件要在上面# 這個request 就是當次請求的request# 取出ipip = request.META.get('REMOTE_ADDR')user_agent = request.META.get('HTTP_USER_AGENT')print(ip)print(user_agent)# return HttpResponse('不讓你看了') # 不會再走視圖函數了
#? 能返回的情況:
?????????1 None,表示執行完這個代碼,經過中間件,繼續執行,最后進視圖函數
?????????2 四件套,后續不走了,中間件的process_response---》直接返回給瀏覽器了
# 中間件,在響應頭加入訪問時間:import datetime class AddHeaderMiddleWare(MiddlewareMixin):def process_response(self, request, response):# request中有沒有session? 有# request 如果在視圖函數中,往request中放了值,在這里,就可以取出來 request.xxx# print(request.xxx)# 所有cookie中都帶# response.set_cookie('xxxxx', 'asdfds')# 寫入到響應頭,訪問服務端的時間response['ttt'] = datetime.datetime.now()return response ?# 一定要返回response對象
csrf認證相關
# 概念:csrf是跨站請求偽造
# 攻擊原理:
?? ?-在同一個瀏覽器中,如果登錄了A網站,沒有退出,在B網站中,向A網站發送請求,瀏覽器會自動攜帶A網站的cookie,對于A網站后端來講, 它就分辨不清到底是用戶真實發的請求,還是黑客網站發的請求【都會攜帶用戶真實的cookie】
# 如何防范:
? ?django解決了這個問題,只要發送post請求,必須攜帶一個csrf_token 隨機字符串(后端給的)
# 這個隨機字符串可以帶的位置:
? ? ?? ?1 請求體中(urlencoded,form-data):{csrfmiddlewaretoken:asdfasdf}
? ? ? ? 2 放在請求頭中:'X-CSRFToken':asdfasdfasd
? ? ? ? 3 ajax提交數據:默認是urlencoded,放在請求體中沒有任何問題? ? ? ? ?$.ajax({method: 'post',data: {username, password, csrfmiddlewaretoken},success: function (res) {console.log(res)}})
????????? 4 ajax提交,使用json格式---》就不能放在請求體中,只能放在請求頭中:
$.ajax({method: 'post',headers:{'X-CSRFToken':csrfmiddlewaretoken},contentType: 'application/json',data: JSON.stringify({username, password}),success: function (res) {console.log(res)}})
# post 提交的數據,都是從request.POST中取,前提是:必須是urlencoded和form-data格式
# 如果使用ajax發送請求:?
?? ?????????????????redirect ?render就用不了了
? ? ????????????????盡量使用JsonResponse
Auth的使用
# 概念:Auth就是django 的一個app,做用戶管理
# 作用:Auth模塊是Django自帶的用戶認證模塊
????????我們在開發一個網站的時候,無可避免的需要設計實現網站的用戶系統。此時需要實現包括用戶注冊、用戶登錄、用戶認證、注銷、修改密碼等功能,這還真是個麻煩的事情呢。Django作為一個完美主義者的終極框架,當然也會想到用戶的這些痛點。它內置了強大的用戶認證系統–auth,它默認使用 auth_user 表來存儲用戶數據
# 默認的用戶表示auth_user,創建一個用戶:可以用代碼,可以用命令
# 模塊常用方法:
authenticate():一般需要username 、password兩個關鍵字參數????????提供了用戶認證功能,即驗證用戶名以及密碼是否正確,如果認證成功(用戶名和密碼正確有效),便會返回一個 User 對象, authenticate()會在該 User 對象上設置一個屬性來標識后端已經認證了該用戶,且該信息在后續的登錄過程中是需要的。
user = authenticate(username='usernamer',password='password')
login(HttpRequest, user):
????????登錄認證通過,調用一下這個方法,以后從request.user中才能取出當前登錄用戶
logout(request): 退出,一定要調用
is_authenticated():
????????判斷當前用戶是否登錄--不能使用request.user 是否有值來判斷,因為他一直有值
request.user.is_authenticated()
orm的鏈接方式
django的orm的 __ 鏈表,使用什么鏈接方式?
????????在Django ORM中,雙下劃線連接語法本身并不直接對應特定的SQL連接類型。當使用雙下劃線時,Django ORM會根據模型之間的關系和查詢的具體情況自動選擇適當的SQL連接方式,包括INNER JOIN、LEFT OUTER JOIN等。
????????在實際使用中,我們通常涉及到 INNER JOIN(內連接)和 LEFT OUTER JOIN(左連接),因為這兩者是最常見的連接方式。INNER JOIN 用于匹配兩個表中符合條件的行,而 LEFT OUTER JOIN會返回左表中的所有行,以及右表中與左表匹配的行。
中間件+logru案例
記錄用戶訪問所用接口用的時間---》記錄到日志中---》logru---》打印出來即可
????????- ip ?user-agent ?total_time
pip install loguru # 安裝loguru模塊
middle_key.py from django.utils.deprecation import MiddlewareMixin from app01 import models from loguru import logger import datetimeclass MyMiddlew(MiddlewareMixin):def process_request(self, request):addr = request.META.get('REMOTE_ADDR')llq = request.META.get('HTTP_USER_AGENT')request.time = datetime.datetime.now()models.ShuJu.objects.create(ShuJu_REMOTE_ADDR=addr, user_agent=llq)logger.add('runtime_{time}.log', retention=10) # 文件名,創十個logger.info('進入時間為:{}', request.time)def process_response(self, request, response):to_time = datetime.datetime.now()time = to_time - request.timeprint(time)logger.warning('結束時間{}', time)return response
auth模塊案例
如果用戶登錄了,打印用戶的用戶名
log.info('')
# 遷移auth表格 python manage.py createsuperuser
from django.contrib import auth from loguru import logger def demo01(request):if request.method == 'GET':return render(request, 'caojiyh.html')else:username = request.POST.get('username')password = request.POST.get('password')print(password)user = auth.authenticate(request, username=username, password=password)print(user)if user:auth.login(request, user)user=request.userlogger.info('用戶名是{}', user)print(request.user)return redirect('/home/')else:return render(request, 'caojiyh.html', {'error': '用戶名或密碼錯誤'})
IP訪問頻率限制案例
基礎版:總共能訪問5次(數據庫,session)
高級版:做IP訪問頻率限制,一分鐘只能訪問5次