1、本身實現登陸驗證
2、Django自帶的用戶驗證模塊——auth
3、本身動手解決auth不足的地方
1、本身實現登陸驗證
需求:一共有index和login兩個頁面,若是用戶沒有登陸訪問index頁面,則會自動跳轉到login頁面進行登陸,用戶在login登陸以後,會跳轉到index頁面,頁面出現歡迎用戶字樣
分析:數據庫和session相結合,能夠實現不一樣用戶顯示不一樣歡迎字樣。不過本身寫裝飾器太多麻煩,並且若是用戶多的話session的驗證重複步驟就比較多
1.寫入函數
#views.py
from functools import wraps
def check_login(f):
@wraps(f) #取消裝飾器裝飾完成以後,函數名稱改變的問題
def inner(request, *args, **kwargs):
if request.session.get("is_login") == "1": # 若是session中(is_login)對應的value爲1,就執行f()函數,不然,返回登陸頁面
return f(request, *args, **kwargs)
else:
return redirect("/login/")
return inner
def login(request):
if request.method == "POST":
username = request.POST.get("username")
password = request.POST.get("password") #從html中拿到用戶輸入的帳號和密碼
user = models.User.objects.filter(username=username, password=password) # 從數據庫中拿到帳號和密碼和用戶輸入一致的數據
if user: #若是有,則證實用戶帳號密碼正確,若是沒有,就返回登陸頁面
# 登錄成功
request.session["is_login"] = "1" #爲此次登陸設置一個session,key爲is_login,value爲'1'
# request.session["username"] = username
request.session["user_id"] = user[0].id # 爲此次登陸設置一個session,key爲username,value爲數據庫中本帳號密碼保存的id
# 寫上面的一條代碼,django後臺自動作的事情
# 1. 生成特殊的字符串
# 2. 特殊字符串當成key,在數據庫的session表中對應一個session value
# 3. 在響應中向瀏覽器寫了一個Cookie Cookie的值就是 特殊的字符串
return redirect("/index/")
return render(request, "login.html")
@check_login #裝飾器,檢測用戶是否登陸,若是登陸,就執行index函數,若是沒有,就跳轉到登陸頁面
def index(request):
user_id = request.session.get("user_id")
# 根據id去數據庫中查找用戶
user_obj = models.User.objects.filter(id=user_id) # 設置session的時候,把數據庫中的id設爲了session中的key,目的就是在這裏再次獲得id,從數據庫中拿出其它數據
if user_obj:
return render(request, "index.html", {"user": user_obj[0]})
else:
return render(request, "index.html", {"user": "匿名用戶"})
2.補充index.html頁面
# index.html
<!DOCTYPE html>
<html>
<head>
<title>index</title>
</head>
<body>
<h3>This is a test page!</h3>
hello,{{ user.username }}! # 替換登陸的名字
</body>
</html>
3.建立數據表
# models.py
class User(models.Model):
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=20, null=False)
password = models.CharField(max_length=20, null=False)
2、Django自帶的用戶驗證模塊——auth
在使用這個被前輩們封裝好的模塊以前,咱們仍是先來學習一下模塊的基本使用方法吧!
1.建立超級用戶
python manage.py createsuperuser
# 超級用戶數據表(auth_user)是django自動幫忙建立的,可是不能夠直接往裏面寫入數據哦!
# 由於直接寫入的話,密碼是明文顯示的,而通常來講,密碼須要以加密形式保存到數據庫中
# 如:username='username', password='$MqFtX/a3inUsPdJekYDMh8H4ZkohfCl3Lc4Vj5jZuNI='
2.authenticate()
from django.contrib import auth #導入auth模塊
# 驗證用戶名和密碼,若是驗證成功,獲得的是一個用戶對象,若是驗證失敗,獲得的是匿名用戶,取它的任意字段都是空
auth.authenticate(username='theuser',password='thepassword')
若是認證信息有效,會返回一個 User 對象。authenticate()會在User 對象上設置一個屬性來標識後端已經認證了該用戶,且該信息在後續的登陸過程當中是須要的。
3.login(HttpRequest, user)
auth.login(request, user)
# 將驗證的用戶注入request.user屬性
# 該函數接受一個HttpRequest對象,以及一個認證了的User對象
# 此函數使用django的session框架給某個已認證的用戶附加上session id等信息。
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
...
else:
# Return an 'invalid login' error message.
...
4.logout(request) 註銷用戶
# 該函數接受一個HttpRequest對象,無返回值。
# 當調用該函數時,當前請求的session信息會所有清除。
# 該用戶即便沒有登陸,使用該函數也不會報錯。
from django.contrib.auth import logout
def logout_view(request):
logout(request)
# Redirect to a success page.
5.user對象的 is_authenticated()
要求:
1 用戶登錄後才能訪問某些頁面,
2 若是用戶沒有登陸就訪問該頁面的話直接跳到登陸頁面
3 用戶在跳轉的登錄界面中完成登錄後,自動訪問跳轉到以前訪問的地址
方法1:
def my_view(request):
if not request.user.is_authenticated():
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
方法2:
from django.contrib.auth.decorators import login_required
@login_required # django已經爲咱們設計好了一個用於此種狀況的裝飾器:login_requierd()
def my_view(request):
...
# 若用戶沒有登陸,則會跳轉到django默認的登陸URL '/accounts/login/ '
# 默認url能夠在settings.py文件中經過LOGIN_URL進行修改(
在settings.py中加入 LOGIN_URL = '/login/'
)
# 登錄成功後,會重定向到該路徑
注意:
1. 若是是真正的 User 對象,返回值恆爲 True 。 用於檢查用戶是否已經經過了認證。經過認證並不意味着用戶擁有任何權限,這個方法甚至也不檢查該用戶是否處於激活狀態,只是代表用戶成功的經過了認證。
2. 這個方法很重要, 在後臺用request.user.is_authenticated()判斷用戶是否已經登陸,若是true則能夠向前臺展現request.user.name
6.使用create_user輔助函數建立用戶
def register(request):
from django.contrib.auth.models import User
user = User.objects.create_user(username='abcd', password='999999999') # 這裏把它寫死了,實際中要從頁面中post過來,獲得用戶輸入的帳號和密碼
# user = User.objects.create_user(username='',password='',email='') # email能夠不寫,password至少8個字符,password用哈希算法保存到數據庫
# 這裏建立用戶一共有三種:1. create() 密碼明文保存; 2. create_superuser() 建立超級用戶 3. create_user() 建立普通用戶
return HttpResponse('successful!')
7.使用check_password(passwd)檢查密碼
def register(request):
from django.contrib.auth.models import User
user_obj = User.objects.create_user(username='abcd', password='999999999')
user_obj.check_password('888888888') # --->返回false
user_obj.check_password('999999999') # --->返回true,爲了演示,這裏一樣也把數值給寫死了
8.使用 set_password() 來修改密碼
user = User.objects.get(username='') # 獲得要修改密碼的對象
user.set_password(password='') # 從新設置密碼
user.save() # 保存
3、auth_user字段不夠的解決方案
1.一對一表
from django.contrib.auth.models import User
class UserDetail(models.Model):
phone = models.CharField(max_length=11)
user = models.OneToOneField(to=User) #這裏關聯的User就是上面導入的User
2.類的繼承(繼承auth_user表)
from django.contrib.auth.models import User,
AbstractUser
class UserInfo(AbstractUser):
phone = models.CharField(max_length=11)
# 若是使用繼承的方式,須要在settings.py中配置 默認用戶認證時使用的是哪張表
# AUTH_USER_MODEL = 'app01.UserInfo'
# 另外使用這種方法以前,要把auth本身建立的user表刪除才能夠
# 做用:替代auth_user並擴展功能
4、未處理的兩點內容
is_staff : 用戶是否擁有網站的管理權限.
is_active : 是否容許用戶登陸, 設置爲``False``,能夠不用刪除用戶來禁止 用戶登陸
簡單示例
def sign_up(request):
state = None
if request.method == 'POST':
password = request.POST.get('password', '')
repeat_password = request.POST.get('repeat_password', '')
email=request.POST.get('email', '')
username = request.POST.get('username', '')
if User.objects.filter(username=username):
state = 'user_exist'
else:
new_user = User.objects.create_user(username=username, password=password,email=email)
new_user.save()
return redirect('/book/')
content = {
'state': state,
'user': None,
}
return render(request, 'sign_up.html', content)
註冊示例代碼
@login_required
def set_password(request):
user = request.user
state = None
if request.method == 'POST':
old_password = request.POST.get('old_password', '')
new_password = request.POST.get('new_password', '')
repeat_password = request.POST.get('repeat_password', '')
if user.check_password(old_password):
if not new_password:
state = 'empty'
elif new_password != repeat_password:
state = 'repeat_error'
else:
user.set_password(new_password)
user.save()
return redirect("/log_in/")
else:
state = 'password_error'
content = {
'user': user,
'state': state,
}
return render(request, 'set_password.html', content)