昨日內容回顧
# 作用:就是保存用戶信息,保存一系列數據,還可以做緩存 保留一段時間
# session是基于cookie工作的
1. 數據是保存在服務端
2. 存儲的介質:
01 文件
02 數據庫
03 redis
3. 如果以后項目中使用了負載均衡,注意考慮是否有session共享的問題
# 如何使用session:
1. 設置session
request.session['username'] = 'aaa'
request.session['id'] = 111
'''
1. 生成一個隨機字符串,
2. 保存數據到數據庫中
session_key session_data
3. 把數據加密處理之后保存的。
'''
2. 獲取session
request.session['username']
# session設置的時候,是被加密的,獲取出來的session值是明文的
'''
1. 先拿到sessionid => session中的隨機字符串 session_key
2. 會拿著sessionid的值去表中查詢
如果有數據,進行反解密,在把數據封裝到request.session中,因此,我們直接可以通過request.session['id'] 取值
'''
# 以上操作是在中間件中處理的,sessionmiddleware
# 如何設置session的過期時間
request.session.set_expity(120)
# 設置會話Session和Cookie的超時時間
'''
request.session.set_expiry(value)
* 如果value是個整數,session會在些秒數后失效
* 如果value是個datatime或timedelta,session就會在這個時間后失效
* 如果value是0,用戶關閉瀏覽器session就會失效
* 如果value是None,session會依賴全局session失效策略
'''
# FBV:直接在函數的頭上面添加裝飾器的名稱
# CBV:添加裝飾器與FBV添加裝飾器是有區別的
cbv添加裝飾器需要借助于一個裝飾器
from django.utils.decorators import method_dectorator
'''drf:django rest framework => '''
from django.views import View
'''
請求方式:8種, get, post,
options
put
patch
在前后端分離項目中,會出現跨域問題 簡單請求,復雜請求
'''
@method_decorators(login_auth, 'get')
@method_decorators(login_auth, 'post')
@method_decorators(login_auth, 'patch')
class IndexView(View):
# 重寫父類的方法
@method_decorators() # 給IndexView所有的方法添加裝飾器
def dispatch(self, request, *args, **kwargs):
# 依據:mro列表
return super().dispatch(request, *args, **kwargs):
@method_decorators(login_auth)
def get(self, request):
return HttpResponse('ok')
# 1. 中間件的位置在哪里?在路由層之前
django提供了7個中間件,在配置文件中,我們是可以查詢這七個中間件的源碼的
# 2. csrf的中間件, 針對于post請求的提交做csrf的校驗
# 3. 支持我們自定義中間件
3.1 在任意一個應用下,創建一個py文件
3.2 寫一個類,類里面有2個方法,類必須繼承middlewaremixin
3.3 去配置文件中注冊中間件
# 需要我們掌握的是2個方法:
1. process_request
# 請求來的時候,會按照中間的注冊順序,依次從上往下執行
2. procesS_resposne
# 請求走的時候,會按照中間件的注冊順序,依次從下往上執行。
'''
視圖函數在所有中間件的process_request之后,所有中間件的process_response之前
'''
# 如果我們在某一個中間件中的process_reqeust返回了值,之后的中間件都不在走了,然后再走同級別的process_response方法
# 以下3個都不重要(了解)
3. process_view
4. process_template
5. process_excption
# 使用場景:
1. 對全棧做權限校驗
2. 頻率限制
3. 認證
今日內容概要
- csrf跨站請求
- csrf的處理(提供的有相關裝飾器)
- Auth模塊
- B端產品(business,eg:crm,)
- C端產品(consumer面向用戶的,eg:淘寶,京東,租號玩)
內容詳細
1. csrf跨站請求
# 背景:
釣魚網站
'''
英語4級報名網站為例
你要在這個網站要付費,你去的這個網站是一個冒牌的網站,就去冒牌網站里面付費了,錢付到了冒牌網站,但是沒有報名成功
'''
會出現在form表單中,action參數:朝后端發送的地址
# 怎么解決這個問題?
csrf是針對與post請求的才會做驗證
"""
token相關的報錯:
一般都是一個串:秘鑰 私鑰 公鑰...
"""
# 兩種解決方式
# views.py中添加功能:
def index(request):
return render(request, 'index.html')
# urls.py中添加路由:
url(r'^index/', views.index),
# 新建index.html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
{#<form action="" method="post">#}
{# {% csrf_token %} {# 解決csrf_token相關報錯 方法一 #}
{# <p>username<input type="text" name="username"></p>#}
{# <p>password<input type="text" name="password"></p>#}
{# <input type="submit">#}
{#</form>#}
<button class="btn">ajax</button>
<script> {# 解決csrf_token相關報錯 方法二 #}
$('.btn').click(function () {
$.ajax({
url: '',
type: 'post',
{#data:{'a':1, 'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()}, {# 有form表單這樣寫 #}
data: {'a': 1, 'csrfmiddlewaretoken': '{{ csrf_token }}'}, {# 沒有form表單這樣寫 #}
success: function () {
}
})
})
</script>
</body>
</html>


2. csrf相關裝飾器
# 如果使用中間件限制的話,就會限制全局的,要么全部限制,要么全部不限制
# 兩種情況
只有index函數需要驗證,其他的不需要驗證
只想讓home函數不驗證,其他的都需要驗證
# 提供了2個裝飾器
csrf_protect: 需要驗證
csrf_exempt: 不需要驗證
'''按照FBV和CBV的使用即可'''
# 在views.py中測試:
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator
from django.views import View
'''
針對CBV:
csrf_protect的三種方式都是可以的
csrf_exempt前兩種方式都不行,只有第三種方式可以的
'''
# @method_decorator(csrf_protect, 'post') # 2.針對CBV需要驗證 方式二
# @method_decorator(csrf_exempt, 'post') # 5.這種方式也不行
# class IndexView(View):
# @method_decorator(csrf_protect) # 1.針對CBV需要驗證 方式一
# @method_decorator(csrf_exempt) # 4.這種方式不可以
# def post(self, request):
# return HttpResponse('post')
class IndexView(View):
# @method_decorator(csrf_protect) # 3.針對CBV需要驗證 方式三
@method_decorator(csrf_exempt) # 6.這種方式是可以的
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def post(self, request):
return HttpResponse('post')
3. Auth模塊
# 遷移數據庫會有一個表生成,auth_user
# django項目創建完后之后,會有一個默認的路由,admin/
# admin/是django默認提供的后臺管理界面
# 訪問admin/
登錄參照的數據就是從auth_user表中來,前提是必須是超級管理員
# 如何創建超級管理員?
python3 manage.py createsuperuser



# auth模塊實現登錄功能
# 在views.py中測試:
def home(request):
return render(request, 'home.html')
from django.contrib import auth
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 1.去哪個表查詢登錄數據:auth_user
# 2.密碼如何比對
"""
注意事項:
用戶名與密碼必須兩者同時傳入
"""
obj = auth.authenticate(request, username=username, password=password)
# print(obj) # None 密碼不正確返回的值 結果是當前對象
# print(obj) # root 密碼正確返回的值 結果是當前對象
# print(obj.username)
# print(obj.password)
if obj:
# 保存用戶信息 auth模塊有全套功能需要使用
auth.login(request, obj) # 相當于保存了用戶信息
"""
一旦執行了上面的這句話 就可以在全局任何地方 通過request.user 拿到用戶對象
"""
return redirect('/home/')
return render(request, 'login.html')
# login.html內容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<form action="" method="post">
<p>username:<input type="text" name="username"></p>
<p>password:<input type="text" name="password"></p>
<input type="submit">
</form>
</body>
</html>
# urls.py添加路由:
url(r'^home/', views.home),
url(r'^login/', views.login),
# home.html寫入:
body標簽內:<h1>home頁</h1>


# auth模塊驗證是否登錄(裝飾器)
from django.contrib.auth.decorators import login_required
"""
登錄裝飾器跳轉的地址有兩種:
1.局部的
@login_required(login_url=login)
2.全局的 在settings.py文件中配置
LOGIN_URL = '/login/'
如果同時存在局部的和全局的 那么優先訪問 局部 的地址
"""
@login_required # 判斷是否登錄裝飾器 代替了下面的 if判斷
def func(request):
# 必須登錄之后才能訪問
print(request.user) # AnonymousUser 未登錄狀態下訪問
print(request.user) # root 用戶名 登錄狀態下訪問
print(request.user.is_authenticated()) # 驗證是否登錄 False True
# if request.user.is_authenticated():
# return HttpResponse('func')
# else:
# return redirect('/login/')
# 添加路由:
url(r'^func/', views.func),

# auth模塊實現修改密碼
@login_required
def set_pwd(request):
if request.method == 'POST':
old_pwd = request.POST.get('old_pwd')
new_pwd = request.POST.get('new_pwd')
again_pwd = request.POST.get('again_pwd')
# 1. 先判斷兩次密碼輸入是否一致
if new_pwd == again_pwd:
# 2. 校驗老密碼是否正確
is_right = request.user.check_password(old_pwd)
print(is_right) # 返回的是布爾值
if is_right:
# 3. 修改密碼
request.user.set_password(new_pwd) # 這句話 并沒有把密碼修改到數據庫里 只是修改了password密碼的屬性
request.user.save() # 這句話才是真正的操作數據了
return redirect('/home/')
return render(request, 'set_pwd.html')
# 添加路由:
url(r'^set_pwd/', views.set_pwd),

# auth模塊實現注銷功能
def logout(request):
# 清空cookie和session
# request.session.delete()
# request.session.flush()
auth.logout(request)
return redirect('/login/')
# 添加路由:
url(r'^logout/', views.logout),
# auth模塊實現注冊用戶功能
from django.contrib.auth.models import User # 相當于使用 auth_user表
def register(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 數據入庫
# User.objects.create(username=username, password=password) # 密碼是明文的
User.objects.create_user(username=username, password=password) # 密碼是加密的
return redirect('/home/')
# 添加路由:
url(r'^register/', views.register),