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学习资料
Feb 08 Python
python实现飞机大战
Sep 11 Python
Python从数据库读取大量数据批量写入文件的方法
Dec 10 Python
Python调用服务接口的实例
Jan 03 Python
Python子类继承父类构造函数详解
Feb 19 Python
Python pip替换为阿里源的方法步骤
Jul 02 Python
Django自带的加密算法及加密模块详解
Dec 03 Python
Pytorch .pth权重文件的使用解析
Feb 14 Python
利用 PyCharm 实现本地代码和远端的实时同步功能
Mar 23 Python
python 解决selenium 中的 .clear()方法失效问题
Sep 01 Python
python中scrapy处理项目数据的实例分析
Nov 22 Python
解决python3安装pandas出错的问题
May 20 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
星际争霸兵种名称对照表
2020/03/04 星际争霸
php桌面中心(二) 数据库写入
2007/03/11 PHP
PHP开发中常用的8个小技巧
2008/08/27 PHP
php下尝试使用GraphicsMagick的缩略图功能
2011/01/01 PHP
php中自定义函数dump查看数组信息类似var_dump
2014/01/27 PHP
php文件缓存类汇总
2014/11/21 PHP
thinkPHP实现的联动菜单功能详解
2017/05/05 PHP
PHP实现基于图的深度优先遍历输出1,2,3...n的全排列功能
2017/11/10 PHP
laravel项目利用twemproxy部署redis集群的完整步骤
2018/05/11 PHP
PHP项目多语言配置平台实现过程解析
2020/05/18 PHP
node.js中的fs.mkdir方法使用说明
2014/12/17 Javascript
JavaScript简单修改窗口大小的方法
2015/08/03 Javascript
仅30行代码实现Javascript中的MVC
2016/02/15 Javascript
JS简单循环遍历json数组的方法
2016/04/22 Javascript
WEB前端开发框架Bootstrap3 VS Foundation5
2016/05/16 Javascript
jQuery实现的省市县三级联动菜单效果完整实例
2016/08/01 Javascript
D3.js实现文本的换行详解
2016/10/14 Javascript
AngularJS实现页面定时刷新
2017/03/14 Javascript
详解VUE项目中安装和使用vant组件
2019/04/28 Javascript
使用vue for时为什么要key【推荐】
2019/07/11 Javascript
jQuery zTree插件快速实现目录树
2019/08/16 jQuery
使用element-ui +Vue 解决 table 里包含表单验证的问题
2020/07/17 Javascript
vue实现公共方法抽离
2020/07/31 Javascript
ant design vue中表格指定格式渲染方式
2020/10/28 Javascript
js简单粗暴的发布订阅示例代码
2021/01/23 Javascript
python2.7安装图文教程
2018/03/13 Python
Python 循环语句之 while,for语句详解
2018/04/23 Python
python获取程序执行文件路径的方法(推荐)
2018/04/26 Python
解决Python网页爬虫之中文乱码问题
2018/05/11 Python
python flask搭建web应用教程
2019/11/19 Python
Python urlencode和unquote函数使用实例解析
2020/03/31 Python
CSS3弹性盒模型开发笔记(三)
2016/04/26 HTML / CSS
工作态度不端正检讨书
2014/10/04 职场文书
催款函范文
2015/06/24 职场文书
MySQL图形化管理工具Navicat安装步骤
2021/12/04 MySQL
Node.js实现爬取网站图片的示例代码
2022/04/04 NodeJs