Django權(quán)限系統(tǒng)auth模塊用法解讀
認(rèn)證系統(tǒng)auth
auth模塊是Django提供的標(biāo)準(zhǔn)權(quán)限管理系統(tǒng),可以提供用戶身份認(rèn)證, 用戶組和權(quán)限管理。auth可以和admin模塊配合使用, 快速建立網(wǎng)站的管理系統(tǒng)。
auth模塊
from django.contrib import auth
django.contrib.auth中提供了許多方法,這里主要介紹其中的三個(gè):
1 authenticate()
提供了用戶認(rèn)證,即驗(yàn)證用戶名以及密碼是否正確,一般需要username password兩個(gè)關(guān)鍵字參數(shù)
如果認(rèn)證信息有效,會返回一個(gè) User 對象。authenticate()會在User 對象上設(shè)置一個(gè)屬性標(biāo)識那種認(rèn)證后端認(rèn)證了該用戶,且該信息在后面的登錄過程中是需要的。當(dāng)我們試圖登陸一個(gè)從數(shù)據(jù)庫中直接取出來不經(jīng)過authenticate()的User對象會報(bào)錯(cuò)的??!
user = authenticate(username='someone',password='somepassword')
2 login(HttpRequest, user)
該函數(shù)接受一個(gè)HttpRequest對象,以及一個(gè)認(rèn)證了的User對象
此函數(shù)使用django的session框架給某個(gè)已認(rèn)證的用戶附加上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. ? ? ...
3 logout(request) 注銷用戶
from django.contrib.auth import logout def logout_view(request): ? logout(request) ? # Redirect to a success page.
該函數(shù)接受一個(gè)HttpRequest對象,無返回值。當(dāng)調(diào)用該函數(shù)時(shí),當(dāng)前請求的session信息會全部清除。該用戶即使沒有登錄,使用該函數(shù)也不會報(bào)錯(cuò)。
4 is_authenticated()
要求:
1 用戶登陸后才能訪問某些頁面,
2 如果用戶沒有登錄就訪問該頁面的話直接跳到登錄頁面
3 用戶在跳轉(zhuǎn)的登陸界面中完成登陸后,自動(dòng)訪問跳轉(zhuǎn)到之前訪問的地址
// 方法一 def my_view(request): ? if not request.user.is_authenticated(): ? ? return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
# django已經(jīng)為我們設(shè)計(jì)好了一個(gè)用于此種情況的裝飾器:login_requier from django.contrib.auth.decorators import login_required @login_required def my_view(request): ? ...
若用戶沒有登錄,則會跳轉(zhuǎn)到django默認(rèn)的 登錄URL '/accounts/login/ ' (這個(gè)值可以在settings文件中通過LOGIN_URL進(jìn)行修改)。并傳遞 當(dāng)前訪問url的絕對路徑 (登陸成功后,會重定向到該路徑)。
User對象
User 對象屬性:username, password(必填項(xiàng))password用哈希算法保存到數(shù)據(jù)庫
is_staff
: 用戶是否擁有網(wǎng)站的管理權(quán)限.is_active
: 是否允許用戶登錄, 設(shè)置為``False``,可以不用刪除用戶來禁止 用戶登錄
is_authenticated()
如果是真正的 User 對象,返回值恒為 True 。 用于檢查用戶是否已經(jīng)通過了認(rèn)證。
通過認(rèn)證并不意味著用戶擁有任何權(quán)限,甚至也不檢查該用戶是否處于激活狀態(tài),這只是表明用戶成功的通過了認(rèn)證。 這個(gè)方法很重要, 在后臺用request.user.is_authenticated()判斷用戶是否已經(jīng)登錄,如果true則可以向前臺展示request.user.name
User
User是auth模塊中維護(hù)用戶信息的關(guān)系模式(繼承了models.Model), 數(shù)據(jù)庫中該表被命名為auth_user.
User表的SQL描述:
CREATE TABLE "auth_user" ( ? ? "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,? ? ? "password" varchar(128) NOT NULL, "last_login" datetime NULL,? ? ? "is_superuser" bool NOT NULL,? ? ? "first_name" varchar(30) NOT NULL,? ? ? "last_name" varchar(30) NOT NULL, ? ? "email" varchar(254) NOT NULL,? ? ? "is_staff" bool NOT NULL,? ? ? "is_active" bool NOT NULL, ? ? "date_joined" datetime NOT NULL, ? ? "username" varchar(30) NOT NULL UNIQUE )
User對象顧名思義即為表示用戶的對象,里面的屬性包括以上幾條:
創(chuàng)建好對象后,django會自動(dòng)生成表,表名為auth_user,包含以上字段。具體的api文檔如下所示:
class models.User User 對象具有如下字段: username 必選。少于等于30個(gè)字符。 用戶名可以包含字母、數(shù)字、_、@、+、.和- 字符。 first_name 可選。 少于等于30個(gè)字符。 last_name 可選。少于30個(gè)字符。 email 可選。郵箱地址。 password 必選。 密碼的哈希及元數(shù)據(jù)。(Django 不保存原始密碼)。原始密碼可以無限長而且可以包含任意字符。參見密碼相關(guān)的文檔。 groups 與Group 之間的多對多關(guān)系。 user_permissions 與Permission 之間的多對多關(guān)系。 is_staff 布爾值。指示用戶是否可以訪問Admin 站點(diǎn)。 is_active 布爾值。指示用戶的賬號是否激活。 is_superuser 布爾值。只是這個(gè)用戶擁有所有的權(quán)限而不需要給他們分配明確的權(quán)限。 last_login 用戶最后一次登錄的時(shí)間。 date_joined 賬戶創(chuàng)建的時(shí)間。當(dāng)賬號創(chuàng)建時(shí),默認(rèn)設(shè)置為當(dāng)前的date/time。
auth模塊提供了很多API管理用戶信息, 在必要的時(shí)候我們可以導(dǎo)入U(xiǎn)ser表進(jìn)行操作, 比如其它表需要與User建立關(guān)聯(lián)時(shí).
from django.contrib.auth.models import User
新建用戶
user = User.objects.create_user(username, email, password)
建立user對象
user.save()
需要調(diào)用save()方法新用戶才會寫入數(shù)據(jù)庫
auth模塊不存儲用戶密碼明文而是存儲一個(gè)Hash值, 比如迭代使用Md5算法.
一般在注冊操作中會用到該方法,實(shí)現(xiàn)注冊一個(gè)用戶,用到的函數(shù)是User.objects.create_user(),在新建用戶的時(shí)候需要判斷用戶是否存在,我的實(shí)現(xiàn)方式是,User.objects.get(username=xxx)去獲取一個(gè)用戶User對象,用try except實(shí)現(xiàn),如果用戶不存在則拋出User.DoesNotExist異常,在這個(gè)異常中進(jìn)行創(chuàng)建用戶的操作。具體代碼如下:
# 注冊操作 from django.contrib.auth.models import User try: ? User.objects.get(username=username) ? data = {'code': '-7', 'info': u'用戶已存在'} except User.DoesNotExist: ? user = User.objects.create_user(username, email, password) ? if user is not None: ? ? user.is_active = False ? ? user.save()
認(rèn)證用戶
先導(dǎo)入函數(shù)
from django.contrib.auth import authenticate
使用關(guān)鍵字參數(shù)傳遞賬戶和憑據(jù):
user = authenticate(username=username, password=password)
認(rèn)證用戶的密碼是否有效, 若有效則返回代表該用戶的user對象, 若無效則返回None.
該方法不檢查is_active標(biāo)志位.
修改密碼
用戶需要修改密碼的時(shí)候 首先要讓他輸入原來的密碼 ,如果給定的字符串通過了密碼檢查,返回 True
def change_password(request): ? ? if request.is_ajax(): ? ? ? ? data = json.loads(request.POST.get('data')) ? ? ? ? oldPassword = data.get('oldPassword') ? ? ? ? newPassword = data.get('newPassword') ? ? ? ? confirmPassword = data.get('confirmPassword') ? ? ? ? if request.user.check_password(oldPassword): ? ? # 判斷舊密碼是否正確 ? ? ? ? ? ? request.user.set_password(newPassword) ? ? ? ? ? ? request.user.save() ? ? ? ? ? ? result = {'status': 0, "info": "密碼修改登錄成功?。?} ? ? ? ? else: ? ? ? ? ? ? result = {'status': 1, "info": "原密碼不正確??!"} ? ? ? ? return HttpResponse(json.dumps(result)) ? ? return render(request, 'changepassword.html')
修改密碼是User的實(shí)例方法, 該方法不驗(yàn)證用戶身份:
user.set_password(new_password)
通常該方法需要和authenticate配合使用:
user = auth.authenticate(username=username, password=old_password) if user is not None: ? ? user.set_password(new_password) ? ? user.save()
登錄
首先import:
from django.contrib.auth import login
login向session中添加SESSION_KEY, 便于對用戶進(jìn)行跟蹤:
'login(request, user)'
login不進(jìn)行認(rèn)證,也不檢查is_active標(biāo)志位, 一般和authenticate配合使用:
user = authenticate(username=username, password=password) if user is not None: ? ? if user.is_active: ? ? ? ? login(request, user)
在auth/__init__.py中可以看到login的源代碼.
from django.contrib.auth import authenticate, login, logout # 認(rèn)證操作 ca = Captcha(request) if ca.validate(captcha_code): ? user = authenticate(username=username, password=password) ? if user is not None: ? ? if user.is_active: ? ? ? # 登錄成功 ? ? ? login(request, user) ?# 登錄用戶 ? ? ? data = {'code': '1', 'info': u'登錄成功', 'url': 'index'} ? ? else: ? ? ? data = {'code': '-5', 'info': u'用戶未激活'} ? else: ? ? ? data = {'code': '-4', 'info': u'用戶名或密碼錯(cuò)誤'} else: ? data = {'code': '-6', 'info': u'驗(yàn)證碼錯(cuò)誤'}
退出登錄
logout會移除request中的user信息, 并刷新session:
from django.contrib.auth import logout def logout_view(request): ? ? logout(request) from django.contrib.auth import authenticate, login, logout def logout_system(request): ? ? """ ? ? 退出登錄 ? ? :param request: ? ? :return: ? ? """ ? ? logout(request) ? ? return HttpResponseRedirect('/')
只允許登錄的用戶訪問
@login_required修飾器修飾的view函數(shù)會先通過session key檢查是否登錄, 已登錄用戶可以正常的執(zhí)行操作, 未登錄用戶將被重定向到login_url指定的位置.
若未指定login_url參數(shù), 則重定向到settings.LOGIN_URL
from django.contrib.auth.decorators import login_required @login_required(login_url='/accounts/login/') def my_view(request): ? ? ...from django.contrib.auth.decorators import login_required @login_required def user_index(request): ? ? """ ? ? 用戶管理首頁 ? ? :param request: ? ? :return: ? ? """ ? ? if request.method == "GET": ? ? ? ? # 用戶視圖實(shí)現(xiàn)
Group
django.contrib.auth.models.Group定義了用戶組的模型, 每個(gè)用戶組擁有id和name兩個(gè)字段, 該模型在數(shù)據(jù)庫被映射為auth_group數(shù)據(jù)表。
User對象中有一個(gè)名為groups的多對多字段, 多對多關(guān)系由auth_user_groups數(shù)據(jù)表維護(hù)。Group對象可以通過user_set反向查詢用戶組中的用戶。
我們可以通過創(chuàng)建刪除Group對象來添加或刪除用戶組。
# add group = Group.objects.create(name=group_name) group.save() # del group.delete()
我們可以通過標(biāo)準(zhǔn)的多對多字段操作管理用戶與用戶組的關(guān)系:
- 用戶加入用戶組user.groups.add(group)或group.user_set.add(user)
- 用戶退出用戶組user.groups.remove(group)或group.user_set.remove(user)
- 用戶退出所有用戶組user.groups.clear()
- 用戶組中所有用戶退出組group.user_set.clear()
# 創(chuàng)建組 try: ? ? Group.objects.get(name=role_name) ? ? data = {'code': -7, 'info': u'組名已存在'} except Group.DoesNotExist: ? ? groups = Group.objects.create(name=role_name) ? ? if log_manage == 'true': ? ? ? ? permission = Permission.objects.get(codename='access_log') ? ? ? ? groups.permissions.add(permission) ? ? if role_manage == 'true': ? ? ? ? permission = Permission.objects.get(codename='access_role_manage') ? ? ? ? groups.permissions.add(permission) ? ? if user_manage == 'true': ? ? ? ? permission = Permission.objects.get(codename='access_user_manage') ? ? ? ? groups.permissions.add(permission) ? ? if get_users is not None: ? ? ? ? for user in get_users: ? ? ? ? ? ? # 每個(gè)user添加組屬性 ? ? ? ? ? ? db_user = get_object_or_404(User, username=user) ? ? ? ? ? ? db_user.groups.add(groups) ? ? ? ? ? ? data = {'code': 1, 'info': u'添加成功'} ? ? return HttpResponse(json.dumps(data))
Permission
Django的auth系統(tǒng)提供了模型級的權(quán)限控制, 即可以檢查用戶是否對某個(gè)數(shù)據(jù)表擁有增(add), 改(change), 刪(delete)權(quán)限。
auth系統(tǒng)無法提供對象級的權(quán)限控制, 即檢查用戶是否對數(shù)據(jù)表中某條記錄擁有增改刪的權(quán)限。如果需要對象級權(quán)限控制可以使用django-guardian.
假設(shè)在博客系統(tǒng)中有一張article數(shù)據(jù)表管理博文, auth可以檢查某個(gè)用戶是否擁有對所有博文的管理權(quán)限, 但無法檢查用戶對某一篇博文是否擁有管理權(quán)限。
檢查用戶權(quán)限
user.has_perm方法用于檢查用戶是否擁有操作某個(gè)模型的權(quán)限:
user.has_perm('blog.add_article') user.has_perm('blog.change_article') user.has_perm('blog.delete_article')
上述語句檢查用戶是否擁有blog這個(gè)app中article模型的添加權(quán)限, 若擁有權(quán)限則返回True。
has_perm僅是進(jìn)行權(quán)限檢查, 即是用戶沒有權(quán)限它也不會阻止程序員執(zhí)行相關(guān)操作。
permission_required修飾器可以代替has_perm并在用戶沒有相應(yīng)權(quán)限時(shí)重定向到登錄頁或者拋出異常。
# permission_required(perm[, login_url=None, raise_exception=False]) @permission_required('blog.add_article') def post_article(request): ? ? pass
每個(gè)模型默認(rèn)擁有增(add), 改(change), 刪(delete)權(quán)限。在django.contrib.auth.models.Permission模型中保存了項(xiàng)目中所有權(quán)限。
該模型在數(shù)據(jù)庫中被保存為auth_permission數(shù)據(jù)表。每條權(quán)限擁有id ,name , content_type_id, codename四個(gè)字段。
管理用戶權(quán)限
User和Permission通過多對多字段user.user_permissions關(guān)聯(lián),在數(shù)據(jù)庫中由auth_user_user_permissions數(shù)據(jù)表維護(hù)。
- 添加權(quán)限: user.user_permissions.add(permission)
- 刪除權(quán)限: user.user_permissions.delete(permission)
- 清空權(quán)限: user.user_permissions.clear()
用戶擁有他所在用戶組的權(quán)限, 使用用戶組管理權(quán)限是一個(gè)更方便的方法。Group中包含多對多字段permissions, 在數(shù)據(jù)庫中由auth_group_permissions數(shù)據(jù)表維護(hù)。
- 添加權(quán)限: group.permissions.add(permission)
- 刪除權(quán)限: group.permissions.delete(permission)
- 清空權(quán)限: group.permissions.clear()
自定義權(quán)限
在定義Model時(shí)可以使用Meta自定義權(quán)限:
class Discussion(models.Model): ? ... ? class Meta: ? ? ? permissions = ( ? ? ? ? ? ("create_discussion", "Can create a discussion"), ? ? ? ? ? ("reply_discussion", "Can reply discussion"), ? ? ? )
在上一點(diǎn)中用到的Permission.objects.get(codename='access_user_manage')是通過權(quán)限模型創(chuàng)建,需要在models中創(chuàng)建一個(gè)權(quán)限類,然后在meta中進(jìn)行定義codename。
class AccessControl(models.Model): ? ? """ ? ? 自定義權(quán)限控制 ? ? """ ? ? class Meta: ? ? ? ? permissions = ( ? ? ? ? ? ? ('access_dashboard', u'控制面板'), ? ? ? ? ? ? ('access_log', u'日志管理'), ? ? ? ? ? ? ('access_role_manage', u'角色管理'), ? ? ? ? ? ? ('access_user_manage', u'用戶管理'), ? ? ? ? )
運(yùn)行后,會自動(dòng)在數(shù)據(jù)庫中創(chuàng)建相應(yīng)的表,并且插入數(shù)據(jù)。
在創(chuàng)建好權(quán)限之后,下一步就是在各個(gè)視圖中插入權(quán)限控制代碼了。permission_required(),參數(shù)為當(dāng)前應(yīng)用名.codename。這樣就能控制用戶訪問,如果用戶非法訪問則會清空session退出登錄。
@permission_required('webcenter.access_role_manage') @login_required def role_index(request): ? ? """ ? ? 角色管理首頁 ? ? :param request: ? ? :return: ? ? """
同時(shí)在前端模板頁面中也需要進(jìn)行權(quán)限控制,前端要獲取request對象的話,后端返回就需要使用render函數(shù),render(request,xxx,xxx),具體代碼就如下:
{% if request.user.is_superuser or 'webcenter.access_user_manage' in request.user.get_group_permissions or 'webcenter.access_role_manage' in request.user.get_group_permissions or 'webcenter.access_log' in request.user.get_group_permissions ?%} <li class="treeview"> ? <a href="#" rel="external nofollow" rel="external nofollow" > ? ? ? <i class="fa fa-fw fa-skyatlas"></i> ? ? ? <span>站點(diǎn)管理</span> <i class="fa fa-angle-left pull-right"></i> ? </a> ? <ul class="treeview-menu"> ? {% if request.user.is_superuser or 'webcenter.access_log' in request.user.get_group_permissions %} ? ? ? <li><a href="#" rel="external nofollow" rel="external nofollow" id="log_view">日志管理</a></li> ? {% endif %} ? {% if request.user.is_superuser or 'webcenter.access_role_manage' in request.user.get_group_permissions %} ? ? ? <li><a href="/role/index/" rel="external nofollow" >角色管理</a></li> ? {% endif %} ? {% if request.user.is_superuser or 'webcenter.access_user_manage' in request.user.get_group_permissions %} ? ? ? <li><a href="/user/index/" rel="external nofollow" >用戶管理</a></li> ? {% endif %} </ul> </li> {% endif %}
判斷用戶是否擁有自定義權(quán)限:
user.has_perm('blog.create_discussion')
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Python Django網(wǎng)頁界面協(xié)同過濾推薦算法實(shí)現(xiàn)商品管理與推薦
商品管理與推薦系統(tǒng),本系統(tǒng)使用Python作為主要開發(fā)語言,前端采用HTML、CSS、BootStrap等技術(shù)搭建顯示界面,后端采用Django框架處理用戶的請求響應(yīng)2023-11-11python?sns.countplot()?繪畫條形圖詳情
這篇文章主要介紹了python?sns.countplot()繪畫條形圖詳情,sns.countplot()用于畫類別特征的頻數(shù)條形圖,更多相關(guān)內(nèi)容需要的朋友可以參考一下2022-06-06Python 使用dict實(shí)現(xiàn)switch的操作
這篇文章主要介紹了Python 使用dict實(shí)現(xiàn)switch的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04python3 解決requests出錯(cuò)重試的問題
這篇文章主要介紹了python3 解決requests出錯(cuò)重試的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04