用戶認證之cookie、session以及auth
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登錄示例
views.py文件內容:
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/') #重定向回登錄頁面
login.html文件內容:
<!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模塊實現用戶認證
urls.py文件內容:
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), ]
views.py文件內容:
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")
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, 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>
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, initial-scale=1"> <title>Title</title> </head> <body> <h3>hi {{ name }}</h3> <a href="/logout/">註銷</a> </body> </html>
用戶認證之cookie、session以及auth