天天看點

使用者認證之cookie、session以及auth

一、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>