07+. Django使用者登入驗證系統和登入登出
開啟微信掃一掃,關注微信公眾號【資料與演算法聯盟】
轉載請註明出處:http://blog.csdn.net/gamer_gyt
博主微博:http://weibo.com/234654758
Github:https://github.com/thinkgamer
寫在前邊的話
一直以來對Django的使用者許可權登入保護模稜兩可,最近由於在做一個django的專案,其中涉及到使用者的許可權登入保護,所以算是有些清楚了,總結下來,給還在模稜兩可的你閱讀。
附上我最近一直在commit的github地址:https://github.com/Thinkgamer/CSMarket
環境說明
Django:1.10
Python:3.5
使用者登入驗證
1:前提說明
以下所談到的使用者登入驗證給予擴充套件Django 內建的User模型,以AbstractUser方式擴充套件User模型,Django中的使用者擴充套件的兩種方式可參考:http://blog.csdn.net/gamer_gyt/article/details/50499653
以下程式碼為上邊給的github地址中的例項,抽取其中使用者驗證為例。
2:以AbstractUser方式擴充套件內建User
models.py:
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
# 手機號
user_phone = models.CharField(blank=True, verbose_name='電話', max_length=11)
#判斷是否是認證通過的使用者
user_isValid=models.BooleanField(blank=True,default=False)
def __unicode__(self) :
return self.user.username
admin.py:
from django.contrib import admin
from logre.models import User
admin.site.register(User)
3:authenticate 進行使用者驗證
提供了使用者認證,即驗證使用者名稱以及密碼是否正確。一般需要username password兩個關鍵字引數。
如果認證資訊有效,會返回一個 User 物件。authenticate()會在User 物件上設定一個屬性標識那種認證後端認證了該使用者,且該資訊在後面的登入過程中是需要的。當我們試圖登陸一個從資料庫中直接取出來不經過authenticate()的User物件會報錯的!!
user = authentica(username=’someone’,password=’somepassword’)
那麼使用者登入函式該怎麼寫呢?
views.py
#使用者登入
@csrf_exempt
def login(request):
if request.method=='POST':
uname=request.POST.get('username')
pwd=request.POST.get('passwd')
user = authenticate(username=uname,password=pwd)
if user is not None:
auth_login(request, user)
# 更新最後登入時間
now_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
user.last_login=now_time
user.save()
return HttpResponseRedirect(referer)
else:
return render_to_response('login.html',{
'error': '郵箱或者密碼不正確',
'user_name': uname,
'user_pwd': pwd,
})
else:
return render_to_response('login.html',{})
注意事項:這裡的authentica函式只能接受username和password,因為我在測試email的時候不好使(如果恰巧你看到了這裡,並且驗證可以用email和password驗證的話,請留言)
AbstractUser擴充套件的User模型,在資料庫中密碼儲存形式是經過轉化的,所以我們並不能直接操作密碼,幸好django提供了專門的函式來修改密碼。
set_password 函式
eg:(由於我專案還沒更新到這一步,所以這裡就舉這樣一個簡單的例子)
>>> from django.contrib.auth.models import User
>>> u = User.objects.get(username='john')
>>> u.set_password('new password')
>>> u.save()
4:Permission
Django的auth系統提供了模型級的許可權控制, 即可以檢查使用者是否對某個資料表擁有增(add), 改(change), 刪(delete)許可權。
auth系統無法提供物件級的許可權控制, 即檢查使用者是否對資料表中某條記錄擁有增改刪的許可權。如果需要物件級許可權控制可以使用django-guardian。
假設在部落格系統中有一張article資料表管理博文, auth可以檢查某個使用者是否擁有對所有博文的管理許可權, 但無法檢查使用者對某一篇博文是否擁有管理許可權
user.has_perm方法用於檢查使用者是否擁有操作某個模型的許可權
eg:
user.has_perm('blog.add_article')
user.has_perm('blog.change_article')
user.has_perm('blog.delete_article')
如果要新增許可權的話,我們可以在後臺管理中自己新增,當然也可以使用以下方法新增
user.user_permissions.add()
刪除許可權:
user.user_permissions.delete()
清空許可權
user.user_permissions.clear()
使用者擁有他所在使用者組的許可權, 使用使用者組管理許可權是一個更方便的方法。Group中包含多對多欄位permissions, 在資料庫中由auth_group_permissions資料表維護。
新增許可權
group.permissions.add(permission)
刪除許可權
group.permissions.delete(permission)
清空許可權
group.permissions.clear()
使用者登入和登出
1:Http請求和迴應
2:使用者登入
該函式接受一個HttpRequest物件,以及一個認證了的User物件
此函式使用django的session框架給某個已認證的使用者附加上session id等資訊。
其實在我們上邊的views.py函式中也有看到就是 auth_login(request,user)
前提條件是擴充套件django的User使用者模型,使用時需要匯入django的login
from django.contrib.auth import login as auth_login
PS:我這裡as為auth_login是因為我的views函式為login,否則會重名,會出現錯誤
使用:
uname=request.POST.get('username')
pwd=request.POST.get('passwd')
user = authenticate(username=uname,password=pwd)
if user is not None:
auth_login(request, user)
3:使用者登出
logout:該函式接受一個HttpRequest物件,無返回值。當呼叫該函式時,當前請求的session資訊會全部清除。該使用者即使沒有登入,使用該函式也不會報錯
from django.contrib.auth import logout as auth_logout
def logout(request):
auth_logout(request)
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
4:登入之後保持會話狀態
在其登入之後會將使用者資訊儲存在request中,那麼我們我進行一個views 函式前,可以先判斷下request.user是否存在,如存在將資料傳遞給返回前端,如果不存在我們也可以新增一些其他的邏輯。
def all(request):
if request.user.is_authenticated:
user_name=request.user
else:
user_name=''
return render(request, 'news.html', {
'user_name': user_name,
})
5:如何記錄登入前的來源頁面
這裡我們使用的是:
request.META[‘HTTP_REFERER’]
大概實現的思路是:在login函式內宣告一個全域性變數referer,在不是發生post請求的時候記錄下來源頁面賦值給referer,在是發生post請求後返回到原頁面。程式碼如下:
#使用者登入
@csrf_exempt
def login(request):
global referer
if request.method=='POST':
...
return HttpResponseRedirect(referer)
else:
try:
referer = request.META['HTTP_REFERER'] # 獲取網頁訪問來源
except:
pass
finally:
return render_to_response('login.html',{})
總結
其實Django本身的使用者驗證系統和登入登出功能是十分強大的,在開發過程中如果能利用好這些技術點,必然會節約很多我們的開發時間。