一、cookie和session介紹
cookie不屬于http協定範圍,由于http協定無法保持狀态,但實際情況,我們卻又需要“保持狀态”,是以cookie就是在這樣一個場景下誕生。
cookie的工作原理是:由伺服器産生内容,浏覽器收到請求後儲存在本地;當浏覽器再次通路時,浏覽器會自動帶上cookie,這樣伺服器就能通過cookie的内容來判斷這個是“誰”了。
cookie雖然在一定程度上解決了“保持狀态”的需求,但是由于cookie本身最大支援4096位元組,以及cookie本身儲存在用戶端,可能被攔截或竊取,是以就需要有一種新的東西,它能支援更多的位元組,并且他儲存在伺服器,有較高的安全性。這就是session。
總結而言:cookie彌補了http無狀态的不足,讓伺服器知道來的人是“誰”;但是cookie以文本的形式儲存在本地,自身安全性較差;是以我們就通過cookie識别不同的使用者,對應的在session裡儲存私密的資訊以及超過4096位元組的文本。
二、cookie的簡單使用
1、擷取Cookie
request.COOKIES.get("islogin",None) #如果有就擷取,沒有就預設為none
2、設定Cookie
obj = redirect("/index/")
obj.set_cookie("islogin",True) #設定cookie值,注意這裡的參數,一個是鍵,一個是值
obj.set_cookie("haiyan","344",20) #20代表過期時間
obj.set_cookie("username", username)
3、删除Cookie
obj.delete_cookie("cookie_key",path="/",domain=name) #path定義的是對那些路徑生效,/表示對所有的url路徑
4、cookie的優缺點
優點:資料存儲在用戶端。減輕服務端的壓力,提高網站的性能
缺點:安全性不高,在用戶端很容易被檢視或破解使用者會話資訊
5、cookie登入示例
models.py檔案内容:
class UserInfo(models.Model):
username =models.CharField(max_length=32)
password =models.CharField(max_length=32)
urls.py檔案内容:
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login),
url(r'^index/', views.index),
]
views.py檔案内容:
from django.shortcuts import render,redirect,HttpResponse
from app01 import models
def login(request):
if request.method=="POST":
print("所有請求資料",request.POST)
username = request.POST.get("username")
password = request.POST.get("password")
ret = models.UserInfo.objects.filter(username=username,password=password) #判斷使用者輸入的是否是資料庫中的值
if ret: #如果使用者名和密碼都正确,則登入成功
print(request.COOKIES)
obj = redirect("/index/")
obj.set_cookie("islogin",True) #設定cookie值實作保持狀态,注意這裡的參數,一個是鍵,一個是值
obj.set_cookie("haiyan","344",20) #20代表過期時間
obj.set_cookie("username", username)
return obj
else:
return render(request,"login.html")
else:
return render(request,"login.html")
def index(request):
is_login = request.COOKIES.get("islogin",None) #得到cookie,有就得到,沒有就得到none
if is_login:
username = request.COOKIES.get("username")
return render(request,"index.html",{"username":username})
else:
return redirect("/login/")
login.html檔案内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width">
<title>使用者登入</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
<script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
<style>
.c1{
margin-top: 100px;
}
.btn{
width: 130px;
}
.c2{
margin-left: 40px;
}
</style>
</head>
<body>
<div>
<div>
<div class="c1 col-md-5 col-md-offset-3">
<form action="/login/" method="post" novalidate>
{% csrf_token %}
<div>
<label for="username" class="col-sm-2 control-label">使用者名</label>
<div>
<input type="email" id="username" placeholder="Email" name="username">
</div>
</div>
<div>
<label for="password" class="col-sm-2 control-label">密碼</label>
<div>
<input type="password" name="password" id="password"
placeholder="Password">
</div>
</div>
<div>
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">登入</button>
<button type="submit" class="btn btn-success c2">注冊</button>
</div>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
index.html檔案内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width">
<title>Title</title>
</head>
<body>
<h1>hello{{ username }}</h1>
</body>
</html>
三、session的簡單使用
1、設定session值
request.session["session_name"]="admin"
2、擷取session值
session_name = request.session("session_name")
3、删除session值
del request.session["session_name"] 删除一組鍵值對
request.session.flush() 删除一條記錄
4、檢測是否操作session值
if "session_name" is request.session:
5、使用者session的随機字元串
request.session.session_key
# 将所有Session失效日期小于目前日期的資料删除
request.session.clear_expired()
# 檢查 使用者session的随機字元串 在資料庫中是否
request.session.exists("session_key")
# 删除目前使用者的所有Session資料
request.session.delete("session_key")
request.session.set_expiry(value)
* 如果value是個整數,session會在些秒數後失效。
* 如果value是個datatime或timedelta,session就會在這個時間後失效。
* 如果value是0,使用者關閉浏覽器session就會失效。
* 如果value是None,session會依賴全局session失效政策。
6、session流程分析
session會把資訊儲存在服務端,通常session和cookie配合使用。
(1)session設定
request.session["user_id"]=user.pk
request.session["username"]=user.user
内部實作機制如下:
'''
if request.COOKIE.get("sessionid"): #浏覽器能取到sessionid,對其進行更新操作
更新sessionid的值
else:
{"user_id": 1, "username": "wang"}
第一步: 生成随機字元串: vwerascxh24asdasdasdsd
第二步: 在django-sesion表生成一條記錄:
session - key vwerascxh24asdasdasdsd
session - data {"user_id": 1, "username": "wang"}
第三步:
obj.set_cookie("sessionid", vwerascxh24asdasdasdsd)
'''
(2)session擷取
request.session.get("user_id")
'''
第一步: request.COOKIE.get("sessionid"):vwerascxh24asdasdasdsd
第二步: 在django-sesion表查詢一條記錄:session-key=vwerascxh24asdasdasdsd
第三步: session-data({"user_id":1,"username":"alex"}).get("user_id")
'''
7、session登入示例
def log_in(request):
if request.method == "POST":
username = request.POST['user']
password = request.POST['pwd']
user = UserInfo.objects.filter(username=username, password=password)
if user:
request.session['is_login'] = 'true' #定義session資訊
request.session['username'] = username
return redirect('/backend/') ## 登入成功就将url重定向到背景的url
return render(request, 'login.html')
def backend(request):
print(request.session, "------cookie")
print(request.COOKIES, '-------session')
"""
這裡必須用讀取字典的get()方法把is_login的value預設設定為False,當使用者通路backend這個url先嘗試擷取這個浏覽器對應的session中的
is_login的值。如果對方登入成功的話,在login裡就已經把is_login的值修改為了True,反之這個值就是False的
"""
is_login = request.session.get('is_login', False)
if is_login: # 如果為真,就說明使用者是正常登陸的
cookie_content = request.COOKIES
session_content = request.session
username = request.session['username']
return render(request, 'backend.html', locals())
else:
return redirect('/login/')
def log_out(request):
"""
直接通過request.session['is_login']回去傳回的時候,如果is_login對應的value值不存在會導緻程式異常。是以需要做異常處理
"""
try:
del request.session['is_login'] # 删除is_login對應的value值
#request.session.flush() # 删除django-session表中的對應一行記錄
except KeyError:
pass
return redirect('/login/') #重定向回登入頁面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login/" method="post">
<p>使用者名: <input type="text" name="user"></p>
<p>密碼: <input type="password" name="pwd"></p>
<p><input type="submit"></p>
</form>
</body>
</html>
backend.html檔案内容:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>hello {{ username }}</h3>
<a href="/logout/">登出</a>
</body>
</html>
四、auth子產品
auth_user #儲存了使用者認證所需要的使用者資訊
python manage.py createsuperuser #建立超級使用者指令,然後根據提示輸入相關資訊,資訊儲存在auth_user中
from django.contrib import auth #導入子產品
1、authenticate() :驗證使用者輸入的使用者名和密碼是否相同
提供了使用者認證,即驗證使用者名以及密碼是否正确,一般需要username和password兩個關鍵字參數
如果認證資訊有效,會傳回一個User對象。authenticate()會在User 對象上設定一個屬性辨別那種認證後端認證了該使用者,且該資訊在後面的登入過程中是需要的。
2、login(HttpRequest, user):登入
該函數接受一個HttpRequest對象,以及一個認證了的User對象
此函數使用django的session架構給某個已認證的使用者附加上session id等資訊。
3、logout(request) 登出使用者
該函數接受一個HttpRequest對象,無傳回值。當調用該函數時,目前請求的session資訊會全部清除。該使用者即使沒有登入,使用該函數也不會報錯。
4、user對象的 is_authenticated()
要求:
(1)使用者登入後才能通路某些頁面
(2)如果使用者沒有登入就通路該頁面的話直接跳轉登入頁面
(3)使用者在跳轉的登入界面中完成登入後,自動通路跳轉到之前通路的位址
def my_view(request):
if not request.user.is_authenticated():
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
五、User對象
User 對象屬性:username, password(必填項)password用雜湊演算法儲存到資料庫
is_staff : 使用者是否擁有網站的管理權限.
is_active : 是否允許使用者登入, 設定為``False``,可以不用删除使用者來禁止 使用者登入
1、is_authenticated()
如果是真正的 User 對象,傳回值恒為 True 。 用于檢查使用者是否已經通過了認證。
通過認證并不意味着使用者擁有任何權限,甚至也不檢查該使用者是否處于激活狀态,這隻是表明使用者成功的通過了認證。 這個方法可以 用request.user.is_authenticated()判斷使用者是否已經登入,如果true則可以向前台展示request.user.name
2、建立使用者:create_user
from django.contrib.auth.models import User
user = User.objects.create_user(username='',password='',email='')
3、修改密碼: set_password()
user = User.objects.get(username='')
user.set_password(password='')
user.save
六、基于auth子產品實作使用者認證
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login),
url(r'^index/', views.index),
url(r'^logout/', views.logout),
url(r'^reg/', views.reg),
]
from django.shortcuts import render,redirect
from django.contrib import auth
from django.contrib.auth.models import User
def login(request):
if request.method=="POST":
user=request.POST.get("user")
pwd=request.POST.get("pwd")
print("before", request.user)
user=auth.authenticate(username=user,password=pwd)
if user:
auth.login(request,user) # request.user:目前登入對象
return redirect("/index/")
else:
s = "使用者名和密碼輸入錯誤"
return render(request, "login.html", {"s": s})
return render(request,"login.html")
def index(request):
if not request.user.username:
return redirect("/login/")
print(request.user)
name=request.user.username
return render(request,"index.html",{"name":name})
def logout(request):
auth.logout(request)
return redirect("/login/")
def reg(request):
if request.method=="POST":
username = request.POST.get("username")
password = request.POST.get("password")
User.objects.create_user(username=username,password=password) #得到使用者輸入的使用者名和密碼建立一個新使用者
s = "恭喜你注冊成功,現在可以登入了"
return redirect("/login/")
return render(request,"reg.html")
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
使用者名 <input type="text" name="user">
密碼 <input type="password" name="pwd">
<input type="submit">
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
</head>
<body>
<h3>hi {{ name }}</h3>
<a href="/logout/">登出</a>
</body>
</html>