用戶登錄驗證問題及auth模塊的引入


一、自己實現登錄驗證
二、Django自帶的用戶驗證模塊——auth
三、自己動手解決auth不足的地方
 
 
 
一、自己實現登錄驗證

需求:一共有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)
 
 
 
二、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()    # 保存
 
 
 
三、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並擴展功能
 
 
 
 
四、未處理的兩點內容

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)
 
修改密碼示例
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM