【Django】認證系統

目錄

  • #. auth模塊
    • 1. 認證 authenticate()
    • 2. 登陸 login(HttpRequest, user)
    • 3. 注銷 logout(request)
    • 4. 認證判斷 is_authenticated()
    • 5. 登陸校驗 login_requierd()
    • 6. 創建普通用戶 create_user()
    • 7. 創建超級用戶 create_superuser()
    • 8. 密碼校驗 check_password(password)
    • 9. 修改密碼 set_password(new_password)
  • User對象的屬性
  • 擴展默認的auth_user表
  • auth實現

@
我們在開發一個網站的時候,無可避免的需要設計實現網站的用戶系統。此時我們需要實現包括用戶注冊、用戶登錄、用戶認證、注銷、修改密碼等功能,這還真是個麻煩的事情呢。

Django作為一個完美主義者的終極框架,當然也會想到用戶的這些痛點。它內置了強大的用戶認證系統--auth,它默認使用 auth_user 表來存儲用戶數據。

補充:Django內置的生成當前時間的方法

from django.utils.timezone import now
now_time = now()  # 生成當前時間
# 時間格式示例:2018-11-22 05:17:09.538525+00:00
# 它生成的時間格式能夠與數據庫中的auto_now/auto_now_add生成的時間做計算.


#. auth模塊

# 導入auth模塊
from django.contrib import auth

1. 認證 authenticate()

提供了用戶認證功能,即驗證用戶名以及密碼是否正確,一般需要username 、password兩個關鍵字參數。

如果認證成功(用戶名和密碼正確有效),便會返回一個 User 對象。

authenticate()會在該 User 對象上設置一個屬性來標識后端已經認證了該用戶,且該信息在后續的登錄過程中是需要的。

用法:

# user = auth.authenticate(request, **form_obj.cleaned_data)
user = auth.authenticate(request, username="用戶名", password="密碼")

2. 登陸 login(HttpRequest, user)

該函數接受一個HttpRequest對象,以及一個經過認證的User對象。

該函數實現一個用戶登錄的功能。它本質上會在后端為該用戶生成相關session數據。

session數據表名為:django_session,一個瀏覽器對應一條記錄。

示例:
在這里插入圖片描述
***

3. 注銷 logout(request)

該函數接受一個HttpRequest對象,無返回值。

當調用該函數時,當前請求的session信息會全部清除。該用戶即使沒有登錄,使用該函數也不會報錯。

示例:
在這里插入圖片描述
***

4. 認證判斷 is_authenticated()

用來判斷當前請求是否通過了認證(用戶是否登陸)。

示例:
在這里插入圖片描述
***

5. 登陸校驗 login_requierd()

auth 給我們提供的一個裝飾器工具,用來快捷的給某個視圖添加登錄校驗。

若用戶沒有登錄,則會跳轉到django默認的登錄URL '/accounts/login/ ' ,并傳遞當前訪問url的絕對路徑 (登陸成功后,會重定向到該路徑)。

==如果需要自定義登錄的URL,則需要在settings.py文件中通過LOGIN_URL進行修改,如下:==

# 修改默認的登陸URL為'/login/':
LOGIN_URL = '/login/'

用法:

# 用于驗證是否登陸的裝飾器
from django.contrib.auth.decorators import login_required  @login_required
def home(request):pass

6. 創建普通用戶 create_user()

auth 提供的一個創建新用戶的方法,需要提供必要參數(username、password)等。

示例:
在這里插入圖片描述
***

7. 創建超級用戶 create_superuser()

auth 提供的一個創建新的超級用戶的方法,需要提供必要參數(email, username, password)。

示例:
在這里插入圖片描述
***

8. 密碼校驗 check_password(password)

auth 提供的一個檢查密碼是否正確的方法,需要提供當前請求用戶的密碼。

密碼正確返回True,否則返回False。

示例:
在這里插入圖片描述
***

9. 修改密碼 set_password(new_password)

auth 提供的一個修改密碼的方法,接收 要設置的新密碼 作為參數。

==注意:設置完一定要調用用戶對象的save方法!!!==

示例:
在這里插入圖片描述

User對象的屬性

重要屬性:

  • username:用戶名
  • password:密文密碼
  • is_staff:用戶是否擁有網站的管理權限(是否可登陸admin后臺).
  • is_active:是否允許用戶登陸,設置為False后,可以在不刪除用戶的前提下禁止用戶登陸.
    對禁用的用戶調用auth.authenticate()方法將返回None

==request.user.xx :返回xx字段的值(xx可以為auth_user表中的所有字段名).
request.user :默認返回username字段的值.==

擴展默認的auth_user表

這內置的認證系統這么好用,但是auth_user表字段都是固定的那幾個,我在項目中沒法拿來直接使用啊!

比如,我想要加一個存儲用戶手機號的字段,怎么辦?

聰明的你可能會想到新建另外一張表然后通過一對一和內置的auth_user表關聯,這樣雖然能滿足要求但是有沒有更好的實現方式呢?

答案是當然有了。

我們可以通過繼承內置的 AbstractUser 類,來定義一個自己的Model類。

這樣既能根據項目需求靈活的設計用戶表,又能使用Django強大的認證系統了。

from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):"""用戶信息表"""nid = models.AutoField(primary_key=True)phone = models.CharField(max_length=11, null=True, unique=True)def __str__(self):return self.username

注意:
按上面的方式擴展了內置的auth_user表之后,一定要在settings.py中告訴Django,我現在使用我新定義的UserInfo表來做用戶認證。寫法如下:

# 引用Django自帶的User表,繼承使用時需要設置
AUTH_USER_MODEL = app名.UserInfo'

再次注意:
==一旦我們指定了新的認證系統所使用的表,我們就需要重新在數據庫中創建該表,而不能繼續使用原來默認的auth_user表了。==

auth實現

實現功能:注冊用戶、登陸、注銷、修改密碼、登陸校驗

==settings.py文件增加配置項:==

# 這里配置項目登陸頁面的路由
LOGIN_URL = '/login/'

==urls.py文件:==

from django.conf.urls import url
from django.contrib import admin
from blog import viewsurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^register/$', views.register),url(r'^login/$', views.login),url(r'^index01/$', views.index01),url(r'^index02/$', views.index02),url(r'^logout/$', views.logout),url(r'^change_password/$', views.change_password),url(r'^ajax_register/$', views.ajax_register),
]

==forms.py文件:==

from django import forms
from django.forms import Form
from django.forms import widgets
from django.core.exceptions import ValidationError  # 用于拋出錯誤信息# 用戶登陸驗證
class LoginForm(Form):username = forms.CharField(label="用戶名",min_length=2,max_length=6,error_messages={'required': "用戶名不能為空",'invalid': "用戶名格式錯誤",'min_length': "用戶名最短2位",},  # 自定義錯誤提示)password = forms.CharField(label="密碼",min_length=6,max_length=12,error_messages={'required': "密碼不能為空",'invalid': "密碼格式錯誤",'min_length': "密碼最短6位",},widget=widgets.PasswordInput(),  # 指定input框的type類型password)# 注冊驗證
class RegForm(Form):username = forms.CharField(label="用戶名",min_length=2,max_length=6,error_messages={'required': "用戶名不能為空",'invalid': "用戶名格式錯誤",'min_length': "用戶名最短2位",},  # 自定義錯誤提示)password = forms.CharField(label="密碼",min_length=6,max_length=12,error_messages={'required': "密碼不能為空",'invalid': "密碼格式錯誤",'min_length': "密碼最短6位",},widget=widgets.PasswordInput(),)re_password = forms.CharField(label="確認密碼",min_length=6,max_length=12,error_messages={'required': "驗證密碼不能為空",'invalid': "密碼格式錯誤",'min_length': "密碼最短6位",},widget=widgets.PasswordInput(),)def clean_re_password(self, *args, **kwargs):password = self.cleaned_data.get('password')re_password = self.cleaned_data.get('re_password')if password == re_password:return passwordraise ValidationError("密碼不一致")# 單選按鈕level = forms.fields.ChoiceField(label="用戶級別",choices=((0, "普通用戶"), (1, "超級用戶"),),initial=0,  # 默認選擇普通用戶widget=forms.widgets.RadioSelect(),)# 修改密碼
class ChangePwd(Form):old_password = forms.CharField(label="舊密碼",min_length=6,max_length=12,error_messages={'required': "舊密碼不能為空",'invalid': "密碼格式錯誤",'min_length': "密碼最短6位",},widget=widgets.PasswordInput(),)password = forms.CharField(label="新密碼",min_length=6,max_length=12,error_messages={'required': "新密碼不能為空",'invalid': "密碼格式錯誤",'min_length': "密碼最短6位",},widget=widgets.PasswordInput(),)re_password = forms.CharField(label="確認新密碼",min_length=6,max_length=12,error_messages={'required': "驗證密碼不能為空",'invalid': "密碼格式錯誤",'min_length': "密碼最短6位",},widget=widgets.PasswordInput(),)def clean_re_password(self, *args, **kwargs):password = self.cleaned_data.get('password')re_password = self.cleaned_data.get('re_password')if password == re_password:return passwordraise ValidationError("密碼不一致")

==views.py文件:==

from django.shortcuts import render, redirect, HttpResponse
from blog.forms import *  # 導入自定義的Form組件
from django.contrib import auth  # 導入認證模塊
from django.contrib.auth.models import User  # 導入User表
from django.contrib.auth.decorators import login_required  # 用于驗證是否登陸的裝飾器
from blog072 import settings# 注冊
def register(request):form_obj = RegForm()if request.method == 'POST':form_obj = RegForm(request.POST)if form_obj.is_valid():form_obj.cleaned_data.pop('re_password')level = form_obj.cleaned_data.pop('level')# 判斷要注冊的用戶類型if not int(level):# 使用create()方法創建的用戶為明文密碼,無法登陸(不可使用此方法)# User.objects.create(**form_obj.cleaned_data)# create_user():創建普通用戶User.objects.create_user(is_staff=1, **form_obj.cleaned_data)# is_staff=1:允許登陸后臺(默認不允許)else:# create_superuser():創建超級用戶User.objects.create_superuser(email='', **form_obj.cleaned_data)return redirect('/login/')return render(request, 'register.html', {'form': form_obj})# 登陸
def login(request):form_obj = LoginForm()if request.method == 'POST':form_obj = LoginForm(request.POST)if form_obj.is_valid():# 只有執行了is_valid之后,才可執行cleaned_data方法,且cleaned_data內的數據是經過校驗的user = auth.authenticate(request, **form_obj.cleaned_data)# 如果校驗成功,user是當前登陸用戶對象,否則為None(用戶被禁用[is_active=0]后,也會返回None)if user:# 生成session數據(表名:django_session  一個瀏覽器對應一條session數據)auth.login(request, user)# 如果是跳轉過來的,則登陸成功后返回至原頁面:next = request.GET.get('next')ret = next if next else '/index01/'return redirect(ret)print(form_obj.cleaned_data)return HttpResponse("用戶名或密碼錯誤")return render(request, 'login.html', {'form': form_obj})@login_required
def index01(request):print("用戶%s進入index01頁面" % request.user)# request.user.xx  :xx可以為auth_user表中的所有字段名# request.user 默認返回username字段return render(request, 'index01.html')def index02(request):if not request.user.is_authenticated():# is_authenticated():判斷當前請求是否通過了認證ret = '%s?next=%s' % (settings.LOGIN_URL, request.path)return redirect(ret)print("用戶%s進入index02頁面" % request.user)return render(request, 'index02.html')# 注銷
@login_required
def logout(request):# 注銷,清除session數據auth.logout(request)return redirect('/login/')# 修改密碼
@login_required
def change_password(request):form_obj = ChangePwd()if request.method == 'POST':form_obj = ChangePwd(request.POST)if form_obj.is_valid():old_password = form_obj.cleaned_data.get('old_password')password = form_obj.cleaned_data.get('password')# 判斷舊密碼是否正確if request.user.check_password(old_password):# 修改密碼request.user.set_password(password)request.user.save()  # 同步到數據庫return redirect('/login/')return HttpResponse("舊密碼錯誤!")return render(request, 'change_password.html', {'form': form_obj})# ajax判斷用戶名是否存在
def ajax_register(request):username = request.GET.get('username')print(username)print(User.objects.filter(username=username).exists())if User.objects.filter(username=username).exists():return HttpResponse("0")return HttpResponse()

==HTML文件:==
==注冊頁面(register.html):==

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta http-equiv="content-Type" charset="UTF-8"><meta http-equiv="x-ua-compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"><title>我是注冊頁面</title>
</head>
<body>
<form action="" method="post" novalidate>{% csrf_token %}<p id="sign01">{{ form.username.label }}{{ form.username }}<span style="color: red">{{ form.username.errors.0 }}</span><span id="sign02" style="color: red"></span></p><p>{{ form.password.label }}{{ form.password }}<span style="color: red">{{ form.password.errors.0 }}</span></p><p>{{ form.re_password.label }}{{ form.re_password }}<span style="color: red">{{ form.re_password.errors.0 }}</span></p><p>{{ form.level.label }}{{ form.level }}</p><p><button>注冊</button><span style="font-size: 50%;">注冊成功將返回登陸頁面</span></p>
</form>
{% load static %}
<script src="{% static 'jquery-3.3.1.js' %}"></script>
<script>var $UserName = $('#sign01 input');var $Button = $('button');$UserName.on('input', function () {$.ajax({url: '/ajax_register/',type: 'GET',data: {username: $UserName.val(),csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),},success: function (data) {if (data === '0') {$Button.attr('disabled', 'disabled');$('#sign02').text("用戶名已存在");} else {$Button.removeAttr('disabled', 'disabled');$('#sign02').text('');}},});});
</script>
</body>
</html>

==登陸頁面(login.html):==

{# bootstrap版登陸頁面 #}
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta http-equiv="content-Type" charset="UTF-8"><meta http-equiv="x-ua-compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1">{# 需要下載bootstrap樣式文件 #}<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"><title>我是登陸頁面</title>
</head>
<body>
<form class="form-horizontal" action="" method="post" novalidate>{% csrf_token %}<div class="form-group"><label for="{{ form.username.id_for_label }}" class="col-sm-2 control-label">用戶名</label><div class="col-sm-10">{{ form.username }}{# has-error:Form組件要想展示紅色錯誤信息,必須要加這個類 #}<div class="has-error"><span class="help-block">{{ form.username.errors.0 }}</span></div></div></div><div class="form-group"><label for="{{ form.password.id_for_label }}" class="col-sm-2 control-label">密碼</label><div class="col-sm-10 has-error">{{ form.password }}<div class="has-error"><span class="help-block">{{ form.password.errors.0 }}</span></div></div></div><div class="form-group"><div class="col-sm-offset-2 col-sm-10"><button type="submit" class="btn btn-default">登陸</button><a href="/register/" class="btn btn-sm">注冊用戶</a></div></div>
</form>
</body>
</html>

==index01.py頁面:==

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta http-equiv="content-Type" charset="UTF-8"><meta http-equiv="x-ua-compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"><title>index01</title>
</head>
<body>
<h1>我是 Index01 頁面</h1>
<a href="/logout/">注銷</a>
<a href="/change_password/">修改密碼</a>
</body>
</html>

==index02.py頁面:==

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta http-equiv="content-Type" charset="UTF-8"><meta http-equiv="x-ua-compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"><title>index02</title>
</head>
<body>
<h1>我是 Index02 頁面</h1>
<a href="/logout/">注銷</a>
<a href="/change_password/">修改密碼</a>
</body>
</html>

==修改密碼頁面(change_password.html):==

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta http-equiv="content-Type" charset="UTF-8"><meta http-equiv="x-ua-compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"><title>我是修改密碼頁面</title>
</head>
<body>
<form action="" method="post" novalidate>{% csrf_token %}<p>{{ form.old_password.label }}{{ form.old_password }}<span style="color: red">{{ form.odl_password.errors.0 }}</span></p><p>{{ form.password.label }}{{ form.password }}<span style="color: red">{{ form.password.errors.0 }}</span></p><p>{{ form.re_password.label }}{{ form.re_password }}<span style="color: red">{{ form.re_password.errors.0 }}</span></p><p><button>提交</button><span style="font-size: 50%;">修改成功后將返回登陸頁面</span></p>
</form>
</body>
</html>

轉載于:https://www.cnblogs.com/zyk01/p/10176340.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/249957.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/249957.shtml
英文地址,請注明出處:http://en.pswp.cn/news/249957.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

學習的目的是什么?

學習的目的是為了掌握生存的常識和技能&#xff0c;以便獨立地面對世界&#xff1b; 學習的目的是為了遵從生活的規范和律則&#xff0c;以便和諧地與人相處&#xff1b; 學習的目的是為了探索生命的價值和意義&#xff0c;以便有尊嚴地立于天地之間。 你覺得為什么要學習呢&am…

span里面插入文字

.text-box span::before{ content:attr(data-text);} 轉載于:https://www.cnblogs.com/smzd/p/8491664.html

Spring Boot 動態注入的兩種方式

通過Profilespring.profiles.active spring.profiles.active&#xff1a;官方解釋是激活不同環境下的配置文件&#xff0c;但是實際測試發現沒有對應的配置文件也是可以正常執行的。那就可以把這個key當作一個參數來使用 Profile&#xff1a;spring.profiles.active中激活某配…

kernel devel 安裝與卸載

1、查看系統內核 uname -r 2、查看已安裝kernel-devel uname -a ; rpm -qa kernel\* | sort 3、下載對應的rpm wget xxx/kernel-devel-2.6.32-754.el6.x86_64.rpm 或者 $ sudo yum install "kernel-devel-uname-r $(uname -r)" 4、卸載已安裝的內核 yum remove ker…

彈性布局

/* 開啟彈性布局的換行 */ flex-wrap: wrap;/* 變為多行了 無法使用 align-items 進行位置設置 align-content 在多行的時候 設置屬性 跟 justify-content 一模一樣如果只有 一行時 無法生效 *//* 調整元素 在主軸上的 排布方式flex-end 到主軸的末尾flex-start 默認值center…

詳解 vue-cli 的打包配置文件代碼(給大家寫寫注釋)

一、前言 對于webpack基礎不好&#xff0c;node指令不通的童鞋。估計對自己搭建Vue、react腳手架是相當頭疼的&#xff0c;有種無從下手的感覺。然而&#xff0c;從頭看這2塊&#xff0c;耗時太長&#xff0c;而且說實話得練才行&#xff0c;不練練手看不明白。那大多數人就采取…

AutoFac自動注入時報錯

錯誤描述&#xff1a;An error occurred during the activation of a particular registration 解決辦法&#xff1a;看到了particular這個單詞&#xff0c;用我蹩腳的英語&#xff0c;估計是部分類&#xff1f;結合報錯的兩個類存在互相引用&#xff0c;這就明白了&#xff0c…

嘗試修改源碼需要用到git存一下

git reflog查看本地記錄 git reset --hard 02a3260 轉載于:https://www.cnblogs.com/smzd/p/8492065.html

poj3713 Transferring Sylla 枚舉+tarjan判割點

其實就是判斷是否為三連通圖 三連通圖指的是去掉3個點就不連通的圖&#xff0c;但是并沒有直接求三連通的算法。著名的Tarjan算法可以求解連通和割點&#xff0c;再枚舉刪除一個點就能達到三連通的目的。 先看用例2&#xff0c;是由用例1去掉一條邊而變成非三連通圖的&#xff…

html標簽大全

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>This is study note</title><base href"我是做外鏈的&#xff0c;一般在head里面" target"_blank"><style type&q…

布爾文本搜索

select text from products where Match(# column) Against(#condition bool* IN BOOLEAN MODE); 布爾操作符     包含 必須存在 -    排除,必須不存在(即使包含其他指定的詞也不返回) >    增加排序等級 <    降低排序等級 ()    把詞組成子表達式 …

Linux 安裝Zookeeper單機版(使用Mac遠程訪問)

閱讀本文需要先閱讀安裝Zookeeper<準備> 新建目錄 mkdir /usr/local/zookeeper 解壓 cd zookeeper壓縮包所在目錄 tar -xvf zookeeper-3.4.12.tar.gz -C /usr/local/zookeeper 新建目錄 mkdir /usr/local/zookeeper/zookeeper-3.4.12/data 配置文件準備 cp /usr/local/zo…

深入vue

轉載于:https://www.cnblogs.com/smzd/p/8547748.html

java全棧

前端&#xff1a;HTML/HTML5、CSS/CSS3、Javascript、jQuery、RequireJS、AngularJS、Vue 后端&#xff1a;Java、Struts2/Spring MVC、JPA/Mybatis、Spring Boot 安全&#xff1a;Shiro、Spring Security 中間件&#xff1a;Dubbo、ActiveMQ/RabbitMQ、Nginx 數據庫&#…

vue與webpack

由于最近在vue-cli生成的webpack模板項目的基礎上寫一個小東西&#xff0c;開發過程中需要改動到build和config里面一些相關的配置&#xff0c;所以剛好趁此機會將所有配置文件看一遍&#xff0c;理一理思路&#xff0c;也便于以后修改配置的時候不會“太折騰”。 Vue-webpack項…

size_t為什么重要

參考&#xff1a;https://www.zhihu.com/question/24773728/answer/66535663前言&#xff1a;使用size_t可能會提高代碼的可移植性、有效性或者可讀性&#xff0c;或許同時提高這三者。在標準C庫中的許多函數使用的參數或者返回值都是表示的用字節表示的對象大小&#xff0c;比…

html--form表單常用操作

form表單 用于收集用戶信息&#xff0c;如&#xff1a;登錄、注冊等場景&#xff1b;所有要提交的數據都必須放在form標簽中<form action" " method" "> action&#xff1a;提交地址、動作&#xff0c;與input標簽中type標簽的submit屬性相關聯。 &…

MySQL觸發器(轉載)

觸發器&#xff08;trigger&#xff09;是數據庫中的一個很重要的、很實用的基于事件的處理器&#xff0c;在處理一些業務需求的時候&#xff0c;使用觸發器會很方便。似乎在《高性能MySQL》中&#xff0c;對觸發器作了一定的描述&#xff0c;也提到使用中的一些優勢和局限性&a…

神級bug解決方法

真的是神級bug,util包中的Arrays類導入不了&#xff0c;一直報錯。原因&#xff1a;JDK 1.8和Myeclipse 8.5不兼容&#xff0c;導致java.util.Arrays類無法被編譯。所以報錯。解決方法&#xff1a;1.降低jdk版本。2.升高Myeclipse版本轉載于:https://www.cnblogs.com/yanlongw/…

es6注意點

補救方法&#xff1a; 詳情&#xff1a;http://es6.ruanyifeng.com/#docs/array 取出文本內容 實現深拷貝 jq實現不完全深拷貝 jQuery.extend jQuery.fn.extend function () {var options, name, src, copy, copyIsArray, clone,target arguments[0] || {},i 1,length ar…