django认证系统 Authentication使用详解


Posted in Python onJuly 22, 2019

前言

Django自带一个用户认证系统,用于处理用户账户、群组、许可和基于cookie的用户会话。

Django的认证系统包含了身份验证和权限管理两部分。简单地说,身份验证用于核实某个用户是否合法,权限管理则是决定一个合法用户具有哪些权限。往后,‘认证'这个词同时代指上面两部分的含义。

Django的认证系统主要包括下面几个部分:

  • 用户
  • 许可
  • 可配置的密码哈希系统
  • 用于用户登录或者限制访问的表单和视图工具
  • 可插拔的后台系统

类似下面的问题,不是Django认证系统的业务范围,请使用第三方工具:

  • 密码强度检查
  • 登录请求限制
  • 第三方认证

默认情况下,使用django-admin startproject命令后,认证相关的模块已经自动添加到settings文件内了,如果没有的话,请手动添加。

在INSTALLED_APPS配置项中添加:

  • 'django.contrib.auth': 包含认证框架的核心以及默认模型
  • 'django.contrib.contenttypes':内容类型系统,用于给模型关联许可

在MIDDLEWARE配置项中添加:

  • SessionMiddleware:通过请求管理会话
  • AuthenticationMiddleware:将会话和用户关联

当配置正确后,运行manage.py migrate命令,创建用户认证系统相关的数据库表以及分配预定义的权限。

一、用户对象

用户对象是Django认证系统的核心!在Django的认证框架中只有一个用户模型也就是User模型,它位于django.contrib.auth.models。

本节内容叙述的所有功能,都是基于这个User模型的,和这个User模型没有任何关系的自定义用户模型是无法使用Django认证系统的功能的!

用户模型主要有下面几个字段:

  • username
  • password
  • email
  • first_name
  • last_name

1. 创建用户

要创建一个新用户,最直接的办法是使用create_user()方法:

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')
# 这时,user是一个User类的实例,已经保存在了数据库内,你可以随时修改它的属性,例如:
>>> user.last_name = 'Lennon'
>>> user.save()

如果你已经启用了Django的admin站点,你也可以在后台创建用户。

2. 创建超级用户

使用createsuperuser命令,创建超级用户:

$ python manage.py createsuperuser

或者

$ python manage.py createsuperuser --username=joe --email=joe@example.com

根据提示输入名字、密码和邮箱地址。密码要有一定强度

3. 修改密码

Django默认会对密码进行加密,因此,不要企图对密码进行直接操作。

要修改密码,有两个办法:

  • 使用命令行: python manage.py changepassword username。如果不提供用户名,则会尝试修改当前系统用户的密码。
  • 使用set_password()方法:
from django.contrib.auth.models import User
u = User.objects.get(username='john')
u.set_password('new password')
u.save()

同样可以在admin中修改密码。Django提供了views和forms,方便用户自己修改密码。 修改密码后,用户的所有当前会话将被注销。

4. 用户验证

利用authenticate()方法,对用户进行验证。该方法通常接收username与password作为参数。要注意的是,认证的后端可能有好几个,有一项认证通过则返回一个User类对象,一项都没通过或者抛出了PermissionDenied异常,则返回一个None。例如:

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
  # A backend authenticated the credentials
else:
  # No backend authenticated the credentials

二、 权限与授权

Django提供了一个简单的权限系统,并且已经用于它的admin站点,当然你也可以在你的代码中使用。

User模型的对象有两个多对多的字段:groups和user_permissions,可以像下面这样访问他们:

myuser.groups.set([group_list])
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions.set([permission_list])
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

1. 默认权限

默认情况下,使用manage.py migrate命令时,Django会给每个已经存在的model添加默认的权限。 假设你现在有个app叫做foo,有个model叫做bar,使用下面的方式可以测试默认权限:

add: user.has_perm('foo.add_bar')
change: user.has_perm('foo.change_bar')
delete: user.has_perm('foo.delete_bar')

2. 用户组

Django提供了一个django.contrib.auth.models.Group模型,该model可用于给用户分组,实现批量管理。用户和组属于多对多的关系。用户自动具有所属组的所有权限。

3. 在代码中创建权限

例如,为myapp中的BlogPost模型添加一个can_publish权限。

from myapp.models import BlogPost
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType

content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.create(
  codename='can_publish',
  name='Can Publish Posts',
  content_type=content_type,
)

然后,你可以通过User模型的user_permissions属性或者Group模型的permissions属性为用户添加该权限。

4. 权限缓存

权限检查后,会被缓存在用户对象中。参考下面的例子:

from django.contrib.auth.models import Permission, User
from django.shortcuts import get_object_or_404

def user_gains_perms(request, user_id):
  user = get_object_or_404(User, pk=user_id)
  # any permission check will cache the current set of permissions
  user.has_perm('myapp.change_bar')

  permission = Permission.objects.get(codename='change_bar')
  user.user_permissions.add(permission)

  # Checking the cached permission set
  user.has_perm('myapp.change_bar') # False

  # Request new instance of User
  # Be aware that user.refresh_from_db() won't clear the cache.
  user = get_object_or_404(User, pk=user_id)

  # Permission cache is repopulated from the database
  user.has_perm('myapp.change_bar') # True

  ...

三、 在视图中认证用户

Django使用session和中间件关联请求对象中和认证系统。

每一次请求中都包含一个request.user属性,表示当前用户。如果该用户未登陆,该属性的值是一个AnonymousUser实例(匿名用户),如果已经登录,该属性就是一个User模型的实例。

可以使用is_authenticated方法进行判断,如下:

if request.user.is_authenticated:
# Do something for authenticated users.
...
else:
  # Do something for anonymous users.
  ...

1. 如何登录用户

在视图中,使用认证系统的login()方法登录用户。它接收一个HttpRequest参数和一个User对象参数。该方法会把用户的ID保存在Django的session中。下面是一个认证和登陆的例子:

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)
    # 跳转到成功页面
    ...
  else:
    # 返回一个非法登录的错误页面
    ...

2. 如何注销用户

logout(request)[source]:

from django.contrib.auth import logout

def logout_view(request):
  logout(request)
  # Redirect to a success page.

注意,被logout的用户如何没登录,不会抛出错误。 一旦logout,当前请求中的session数据都会被清空。

3. 限制用户的访问权限

很多时候,我们要区分已登录用户和未登录用户,只对登录的用户开放一些页面或功能,限制未登录用户的行为。办法有很多,下面是主要几种:

1.原始的办法:

如果用户未登录,重定向到登录页面,如下所示:

from django.conf import settings
from django.shortcuts import redirect

def my_view(request):
  if not request.user.is_authenticated:
    return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
  # ...

或者显示一个错误信息:

from django.shortcuts import render

def my_view(request):
  if not request.user.is_authenticated:
    return render(request, 'myapp/login_error.html')
  # ...

2. 使用装饰器

原型:login_required(redirect_field_name='next', login_url=None)[source]

被该装饰器装饰的视图,强制要求用户必须登录后才可以访问。

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
  ...

该装饰器工作机制:

  • 如果用户未登陆,重定向到settings.LOGIN_URL,传递当前绝对路径作为url字符串的参数,例如:/accounts/login/?next=/polls/3/
  • 如果用户已经登录,执行正常的视图

此时,默认的url中使用的参数是“next”,如果你想使用自定义的参数,请修改login_required()的redirect_field_name参数,如下所示:

from django.contrib.auth.decorators import login_required

@login_required(redirect_field_name='my_redirect_field')
def my_view(request):
  ...

如果你这么做了,你还需要重新定制登录模板,因为它引用了redirect_field_name变量。

login_required()装饰器还有一个可选的longin_url参数。例如:

from django.contrib.auth.decorators import login_required

@login_required(login_url='/accounts/login/')
def my_view(request):
  ...

注意:如果不指定login_url参数,请确保你的settings.LOGIN_URL和登陆视图保持正确的关联。例如:

from django.contrib.auth import views as auth_views
url(r'^accounts/login/$', auth_views.login),

3. 使用LoginRequired mixin

通过继承LoginRequiredMixin类的方式限制用户。在多继承时,该类必须是最左边的父类。

from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View):
  login_url = '/login/'
  redirect_field_name = 'redirect_to'

4. 进行测试,根据结果决定动作

也可以直接在视图中进行过滤:

from django.shortcuts import redirect

def my_view(request):
  if not request.user.email.endswith('@example.com'):
    return redirect('/login/?next=%s' % request.path)
  # ...

上面根据用户的邮箱地址,判断用户的权限。

5. 使用权限需求装饰器

Django内置了一个permission_required()装饰器,用户根据用户权限,决定视图的访问权限,如下所示:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote')
def my_view(request):
  ...

权限的格式是<app label>.<permission codename>。

该装饰器还有一个可选的longin_url参数:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', login_url='/loginpage/')
def my_view(request):
  ...

4. 认证视图

Django为我们提供了一系列认证相关的视图,可以直接拿来用,这样你就不需要自己写登录、注销、注册等视图。但是,但是,Django没有为认证视图提供默认的模板,你需要自己写......。

所以,除非懒癌发作,还是老老实实自己写认证相关的视图、路由和模板吧。个人认为类似跟实际生产环境结合非常紧密的视图,根本不需要这种鸡肋的内置视图,到最后,你发现还是要自己写才能满足需求。

所以,后面的部分就不赘述了!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
浅析Python基础-流程控制
Mar 18 Python
用python处理图片实现图像中的像素访问
May 04 Python
python re模块的高级用法详解
Jun 06 Python
浅谈pytorch和Numpy的区别以及相互转换方法
Jul 26 Python
Python3批量生成带logo的二维码方法
Jun 24 Python
django 框架实现的用户注册、登录、退出功能示例
Nov 28 Python
python 实现将小图片放到另一个较大的白色或黑色背景图片中
Dec 12 Python
python pandas利用fillna方法实现部分自动填充功能
Mar 16 Python
Python GUI编程学习笔记之tkinter事件绑定操作详解
Mar 30 Python
使用Python实现批量ping操作方法
May 06 Python
python编写扎金花小程序的实例代码
Feb 23 Python
python中使用asyncio实现异步IO实例分析
Feb 26 Python
django Admin文档生成器使用详解
Jul 22 #Python
django表单的Widgets使用详解
Jul 22 #Python
Python代码使用 Pyftpdlib实现FTP服务器功能
Jul 22 #Python
超简单的Python HTTP服务
Jul 22 #Python
对python 中re.sub,replace(),strip()的区别详解
Jul 22 #Python
django框架CSRF防护原理与用法分析
Jul 22 #Python
全面了解django的缓存机制及使用方法
Jul 22 #Python
You might like
详解PHP的Yii框架中日志的相关配置及使用
2015/12/08 PHP
thinkPHP分组后模板无法加载问题解决方法
2016/07/12 PHP
基于jQuery的固定表格头部的代码(IE6,7,8测试通过)
2010/05/18 Javascript
js有序数组的连接问题
2013/10/01 Javascript
showModelDialog弹出文件下载窗口的使用示例
2013/11/19 Javascript
jQuery制作简单柱状图实例
2015/01/28 Javascript
解决node-webkit 不支持html5播放mp4视频的方法
2015/03/11 Javascript
JavaScript时间转换处理函数
2015/04/14 Javascript
JQuery实现超链接鼠标提示效果的方法
2015/06/10 Javascript
window.setInterval()方法的定义和用法及offsetLeft与style.left的区别
2015/11/11 Javascript
前端性能优化及技巧
2016/05/06 Javascript
JCrop+ajaxUpload 图像切割上传的实例代码
2016/07/20 Javascript
纯js实现手风琴效果代码
2020/04/17 Javascript
Node.js中多进程模块Cluster的介绍与使用
2017/05/27 Javascript
妙用Angularjs实现表格按指定列排序
2017/06/23 Javascript
iscroll动态加载数据完美解决方法
2017/07/18 Javascript
JavaScript基础心法 数据类型
2018/03/05 Javascript
Angular6 正则表达式允许输入部分中文字符
2018/09/10 Javascript
vue 右键菜单插件 简单、可扩展、样式自定义的右键菜单
2018/11/29 Javascript
一文读懂ES7中的javascript修饰器
2019/05/06 Javascript
vue项目中mock.js的使用及基本用法
2019/05/22 Javascript
Vue+Typescript中在Vue上挂载axios使用时报错问题
2019/08/07 Javascript
使用vuex较为优雅的实现一个购物车功能的示例代码
2019/12/09 Javascript
在Vue中使用Echarts实例图的方法实例
2020/10/10 Javascript
原生js实现弹窗消息动画
2020/11/20 Javascript
[14:19]2018年度COSER大赛-完美盛典
2018/12/16 DOTA
python中dir函数用法分析
2015/04/17 Python
详解Python字典的操作
2019/03/04 Python
PyQt5 在label显示的图片中绘制矩形的方法
2019/06/17 Python
python实现差分隐私Laplace机制详解
2019/11/25 Python
pycharm无法安装第三方库的问题及解决方法以scrapy为例(图解)
2020/05/09 Python
Python入门基础之数字字符串与列表
2021/02/01 Python
Java面试题:请问一下代码输出是什么
2015/05/27 面试题
4s店机修工岗位职责
2013/12/20 职场文书
三方合作协议书范本
2014/04/18 职场文书
Redis配置外网可访问(redis远程连接不上)的方法
2022/12/24 Redis