1. 程式人生 > >用戶認證之cookie、session以及auth

用戶認證之cookie、session以及auth

Django cookie 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登錄示例

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