django 验证和授权系统

  • 验证和授权概述
    • 使用授权系统
      • INSTALLED_APPS
      • 中间件
  • User模型
    • 字段
    • User模型的基本用法
      • 创建用户
      • 创建超级用户
      • 修改密码
      • 登录验证:
  • 扩展用户模型
    • 设置Proxy模型
    • 一对一外键:
  • 继承AbstractUser
    • 自定义User
    • 自定义UserManager
    • 修改authenticate的username校验字段
  • 继承自AbstractBaseUser模型
    • 外键使用注意事项
  • 登录、注销和登录限制
    • 登录
    • 注销
    • 登录限制
      • 装饰器登录限制
      • 中间件校验登录
  • 权限
    • 通过定义模型添加权限
    • 通过代码添加权限
    • 用户与权限管理
    • 权限限定装饰器
    • 分组
      • 分组操作

验证和授权概述

Django有一个内置的授权系统,用来处理用户、分组、权限以及基于cookie的会话系统。
Django的授权系统包括验证和授权两个部分,验证是验证这个用户是否是他声称的人(比如用户名和密码验证,角色验证),授权是给与他相应的权限。

Django内置的权限系统包括以下方面

  1. 用户。
  2. 权限。
  3. 分组。
  4. 一个可以配置的密码哈希系统。
  5. 一个可插拔的后台管理系统。

使用授权系统

默认中创建完一个django项目后,其实就已经集成了授权系统。授权系统相关的配置如下:

INSTALLED_APPS

  1. django.contrib.auth:包含了一个核心授权框架,以及大部分的模型定义。
  2. django.contrib.contenttypes:Content Type系统,可以用来关联模型和权限。

中间件

  1. SessionMiddleware:用来管理session。
  2. AuthenticationMiddleware:用来处理和当前session相关联的用户。

User模型

User模型是这个框架的核心部分。完整的路径是在django.contrib.auth.models.User。
User对象包含以下属性:

字段

内置的User模型拥有以下的字段:

  1. username: 用户名。150个字符以内。可以包含数字和英文字符,以及_、@、+、.和-字符。不能为空,且必须唯一!
  2. first_name:歪果仁的first_name,在30个字符以内。可以为空。
  3. last_name:歪果仁的last_name,在150个字符以内。可以为空。
  4. email:邮箱。可以为空。
  5. password:密码。经过哈希过后的密码。
  6. groups:分组。一个用户可以属于多个分组,一个分组可以拥有多个用户。groups这个字段是跟Group的一个多对多的关系。
  7. user_permissions:权限。一个用户可以拥有多个权限,一个权限可以被多个用户所有用。和Permission属于一种多对多的关系。
  8. is_staff:是否可以进入到admin的站点。代表是否是员工。
  9. is_active:是否是可用的。对于一些想要删除账号的数据,我们设置这个值为False就可以了,而不是真正的从数据库中删除。
  10. is_superuser:是否是超级管理员。如果是超级管理员,那么拥有整个网站的所有权限。
  11. last_login:上次登录的时间。
  12. date_joined:账号创建的时间。

User模型的基本用法

创建用户

通过create_user方法可以快速的创建用户。这个方法必须要传递username、email、password。
示例代码如下:

from django.contrib.auth.models import User
user = User.objects.create_user('zhiliao','hynever@zhiliao.com','111111')
# 此时user对象已经存储到数据库中了。当然你还可以继续使用user对象进行一些修改
user.last_name = 'abc'
user.save()


创建超级用户

创建超级用户有两种方式。第一种是使用代码的方式。用代码创建超级用户跟创建普通用户非常的类似,只不过是使用create_superuser。示例代码如下:

from django.contrib.auth.models import UserUser.objects.create_superuser('admin','admin@163.com','111111')

也可以通过命令行的方式。命令如下:

 python manage.py createsuperuser

后面就会提示你输入用户名、邮箱以及密码。

create_user和create_superuser的实现方式,区别就是is_staff和is_superuser字段的设置。

修改密码

因为密码是需要经过加密后才能存储进去的。所以如果想要修改密码,不能直接修改password字段,而需要通过调用set_password来达到修改密码的目的。示例代码如下:

from django.contrib.auth.models import Useruser = User.objects.get(pk=1)
user.set_password('新的密码')
user.save()

登录验证:

Django的验证系统实现了登录验证的功能。
通过django.contrib.auth.authenticate方法只能通过username和password来进行验证。

示例代码如下:

from django.contrib.auth import authenticate
user = authenticate(username='zhiliao', password='111111')
# 如果验证通过了,那么就会返回一个user对象。
if user is not None:# 执行验证通过后的代码
else:# 执行验证没有通过的代码

扩展用户模型

Django内置的User模型虽然已经足够强大了,但是有时候还是不能满足我们的需求。
比如在验证用户登录的时候,django用的是用户名作为验证,而我们有时候需要通过手机号码或者邮箱来进行验证。还有比如我们想要增加一些新的字段,那么我们就需要扩展用户模型了。
扩展用户模型有多种方式。

设置Proxy模型

如果对Django提供的字段,以及验证的方法都比较满意,没有什么需要改的。但是只是需要在他原有的基础之上增加一些操作的方法。那么建议使用这种方式。示例代码如下:

class Person(User):class Meta:proxy = Truedef get_blacklist(self):return self.objects.filter(is_active=False)

在以上,定义了一个Person类继承自User,并且在Meta中设置proxy=True,说明这个只是User的一个代理模型。它并不会影响原来User模型在数据库中表的结构。
以后如果想方便的获取所有黑名单的人,那么就可以通过Person.get_blacklist()就可以获取到。并且User.objects.all()和Person.objects.all()其实是等价的。因为他们都是从User这个模型中获取所有的数据。

一对一外键:

如果对用户验证方法authenticate没有其他要求,就是使用username和password即可完成。但是想要在原来模型的基础之上添加新的字段,那么可以使用一对一外键的方式。示例代码如下:

from django.contrib.auth.models import User
from django.db import models
from django.dispatch import receiver
from django.db.models.signals import post_saveclass UserExtension(models.Model):user = models.OneToOneField(User,on_delete=models.CASCADE,related_name='extension')birthday = models.DateField(null=True,blank=True)school = models.CharField(max_length=100)@receiver(post_save,sender=User)
def create_user_extension(sender,instance,created,**kwargs):if created:UserExtension.objects.create(user=instance)else:instance.extension.save()

以上定义一个UserExtension的模型,并且让它和User模型进行一对一的绑定,以后新增的字段就添加到UserExtension上。
并且还写了一个接受保存模型的信号处理方法,只要是User调用了save方法,那么就会创建一个UserExtension和User进行绑定。

继承AbstractUser

如果对于authenticate不满意,并且不想要修改原来User对象上的一些字段,但是想要增加一些字段,那么这时候可以直接继承自django.contrib.auth.models.AbstractUser,其实这个类也是django.contrib.auth.models.User的父类。
比如想要在原来User模型的基础之上添加一个telephone和school字段。

自定义User

  1. 自定义User模型,继承自AbstractUser,新增字段;
  2. 修改settings.py中的AUTH_USER_MODEL;
  3. 映射数据库表(这种方式因为破坏了原来User模型的表结构,所以必须要在第一次migrate前就先定义好)。

自定义UserManager

如下图,create_user需要传入username,email,password。如果实际需求是通过telephone和password创建用户,就需要自定义UserManager。

  1. 自定义UserManager,继承BaseUserManager,可以参考django的UserManager自定义create_user和create_superuser方法:

    自定义:
class UserManager(BaseUserManager):def _create_user(self, telephone, password, **kwargs):if not telephone:raise ValueError("telephone can't be empty.")if not password:raise ValueError("password can't be empty.")user = self.model(telephone=telephone, **kwargs)user.set_password(password)user.save()return userdef create_user(self, telephone, password, **kwargs):kwargs["is_superuser"] = Falsekwargs["is_staff"] = Truereturn self._create_user(telephone, password, **kwargs)def create_superuser(self, telephone, password, **kwargs):kwargs["is_superuser"] = Truekwargs["is_staff"] = Truereturn self._create_user(telephone, password, **kwargs)
  1. User模型中objects为自定义的UserManager, USERNAME_FIELD=“telephone”
class User(AbstractUser):telephone = models.CharField(max_length=11, unique=True)school = models.CharField(max_length=20)# 自定义UserManagerobjects = UserManager()# 定义authenticate方法中username字段需要传入的值USERNAME_FIELD = "telephone"

修改后:

修改authenticate的username校验字段

在User模型中的定义: USERNAME_FILED = “telephone”

 # 定义authenticate方法中username字段需要传入的值USERNAME_FIELD = "telephone"

继承自AbstractBaseUser模型

  1. 定义User模型,继承AbstractBaseUser, PermissionsMixin; 自定义UserManager通过telephone和password创建用户
from django.contrib.auth.models import AbstractUser, BaseUserManager, PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUserclass UserManager(BaseUserManager):def _create_user(self, telephone, password, **kwargs):if not telephone:raise ValueError("telephone can't be empty.")if not password:raise ValueError("password can't be empty.")user = self.model(telephone=telephone, **kwargs)user.set_password(password)user.save()return userdef create_user(self, telephone, password, **kwargs):kwargs["is_superuser"] = Falsereturn self._create_user(telephone, password, **kwargs)def create_superuser(self, telephone, password, **kwargs):kwargs["is_superuser"] = Truereturn self._create_user(telephone, password, **kwargs)class User(AbstractBaseUser, PermissionsMixin):telephone = models.CharField(max_length=11, unique=True)username = models.CharField(max_length=20)email = models.CharField(max_length=30, unique=True)# 这个字段必须要定义is_active = models.BooleanField(default=True)# 指定authenticate方法的username传入字段USERNAME_FIELD = "telephone"# 命令行创建用户时需要传入的字段,默认是:USERNAME_FIELD + passwordREQUIRED_FIELDS = []# 指定UserManagerobjects = UserManager()# 以下两个方法必须要定义def get_full_name(self):return self.usernamedef get_short_name(self):return self.username
  1. 在settings.py中设置AUTH_USER_MODEL: app_name.model:

  2. 映射到数据库:

  3. 创建user:

  4. authenticate校验用户:

外键使用注意事项

有一个Article模型,需要通过外键引用这个User模型,那么可以通过以下两种方式引用。
第一种就是直接将User导入到当前文件中。示例代码如下:

from django.db import modelsfrom myauth.models import Userclass Article(models.Model):title = models.CharField(max_length=100)content = models.TextField()author = models.ForeignKey(User, on_delete=models.CASCADE)

这种方式是可以行得通的。但是为了更好的使用性,建议还是将User抽象出来,使用get_user_model()动态获取User模型,这个方法会读取settings.AUTH_USER_MODEL。
示例代码如下:

from django.db import models
from django.contrib.auth import get_user_modelclass Article(models.Model):title = models.CharField(max_length=100)content = models.TextField()author = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)

登录、注销和登录限制

登录

在使用authenticate进行验证后,如果验证通过了,会返回一个user对象,拿到user对象后,可以使用django.contrib.auth.login进行登录。

  1. django的login其实也是在登录成功后,cookie中设置了sessionid。
  2. 正常情况下login接口不需要限制csrf_token,所以这里对LoginView过滤了Csrf校验。
  3. 如果remember为1,则设置cookie过期时间为默认的时间(2周),如果remember为0,则设置为关闭浏览器即过期。

forms.py:

from django import forms
from django.core import validatorsfrom book.models import Userclass LoginForm(forms.ModelForm):telephone = forms.CharField(validators=[validators.RegexValidator(regex=r"1[3-9]{1}\d{9}",message="手机号格式有误!")])remember = forms.IntegerField(max_value=1, min_value=0,error_messages={"max_value": "最大值为1!","min_value": "最大值为0!"})class Meta:model = Userfields = ["password"]

views.py:

import json
import tracebackfrom django.contrib.auth import authenticate
from django.contrib.auth import login
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decoratorfrom book.forms import LoginForm@method_decorator(csrf_exempt, name="dispatch")
class LoginView(View):def post(self, request):try:body = json.loads(request.body)form = LoginForm(body)if form.is_valid():telephone = form.cleaned_data.get("telephone")password = form.cleaned_data.get("password")remember = form.cleaned_data.get("remember")user = authenticate(request, username=telephone, password=password)if user:login(request, user)if remember == 1:request.session.set_expiry(None)else:request.session.set_expiry(0)data = {"result": "Login OK!"}return JsonResponse(data)else:# code 30001代表用户名或密码错误,前台根据错误码做国际化data = {"result": "Login Failed!", "code": "30001"}return JsonResponse(data, status=400)# code 30002代表表单校验错误,前台根据错误码做国际化data = {"result": "Login Failed!", "code": "30002"}return JsonResponse(data, status=400)except Exception as err:print("Err:%s, traceback:%s" % (err, traceback.format_exc()))# code 30003代表系统内部错误data = {"result": "Login Failed!", "code": "30003"}return JsonResponse(data, status=500)
  1. 登录成功后,cookie中会有csrftoken和seesionid。

注销

注销、退出登录可以通过django.contrib.auth.logout来实现。它会清理掉这个用户的session数据。

如果在未登录的情况下访问logout会报403。

登录限制

有时候,某个视图函数是需要经过登录后才能访问的,比如logout接口。
有两种实现方法:

  1. 通过django.contrib.auth.decorators.login_required装饰器来实现。
  2. 通过中间件校验用户是否登录。

装饰器登录限制

示例代码如下:

from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required@method_decorator(login_required, name="dispatch")
class LogoutView(View):def post(self, request):try:logout(request=request)data = {"result": "Logout OK!"}return JsonResponse(data)except Exception as err:print("Err:%s, traceback:%s" % (err, traceback.format_exc()))# code 30003代表系统内部错误data = {"result": "Login Failed!", "code": "30003"}return JsonResponse(data, status=500)

中间件校验登录

middlewares.py

from django.http import JsonResponseclass AuthLogin(object):def __init__(self, get_response):self.get_response = get_responseself.white_list = ['/login/', ]  # 白名单self.black_list = ['/black/', ]  # 黑名单def __call__(self, request):request_url = request.path_info# 白名单url或已登录if request_url in self.white_list or request.user.is_authenticated:response = self.get_response(request)return responseelse:data = {"result": "Please login!", "code": "00001"}return JsonResponse(data, status=401)

settings.py:

MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.middleware.gzip.GZipMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware','book.middlewares.AuthLogin'
]

未登录情况下调用/logout/接口:

权限

Django中内置了权限的功能,它的权限都是针对表或者说是模型级别的,比如对某个模型上的数据是否可以进行增删改查操作。
它不能针对数据级别的,比如对某个表中的某条数据能否进行增删改查操作(如果要实现数据级别的,考虑使用django-guardian)。
创建完一个模型后,针对这个模型默认就有三种权限,分别是增/删/改。可以在执行完migrate命令后,查看数据库中的auth_permission表中的所有权限。

其中的codename表示的是权限的名字。name表示的是这个权限的作用。

通过定义模型添加权限

如果我们想要增加新的权限,比如查看某个模型的权限,那么我们可以在定义模型的时候在Meta中定义好。示例代码如下:

class Article(models.Model):title = models.CharField(max_length=100)content = models.TextField()author = models.ForeignKey(get_user_model(),on_delete=models.CASCADE)class Meta:permissions = (('view_article','can view article'),)

通过代码添加权限

权限都是django.contrib.auth.Permission的实例。这个模型包含三个字段,name、codename以及content_type,其中的content_type表示这个permission是属于哪个app下的哪个models。用Permission模型创建权限的代码如下:

from django.contrib.auth.models import Permission,ContentType
from .models import Articlecontent_type = ContentType.objects.get_for_model(Article)
permission = Permission.objects.create(name='可以编辑的权限',codename='edit_article',content_type=content_type)

用户与权限管理

权限本身只是一个数据,必须和用户进行绑定,才能起到作用。
User模型和权限之间的管理,可以通过以下几种方式来管理:

  1. 设置权限的列表:user.user_permissions.set(permission_list)。

  1. 清除所有权限:user.user_permissions.clear()。

  2. 一个个添加权限:myuser.user_permissions.add(permission, permission,…)。

  1. 一个个删除权限:myuser.user_permissions.remove(permission, permission,…)。

  2. 判断是否拥有某个权限:myuser.has_perm(’<app_name>.’),权限参数是一个字符串,格式是app_name.codename。
    如下:pk=2的user只有show权限,没有add权限,通过has_perm可以进行判断。
    注意:超级用户拥有所有权限。

  1. 获取用户所有的权限:myuser.get_all_permissons()。

权限限定装饰器

使用django.contrib.auth.decorators.permission_required可以非常方便的检查用户是否拥有这个权限,如果拥有,那么就可以进入到指定的视图函数中,如果不拥有,那么就会报一个400错误。

示例代码如下:

from django.contrib.auth.decorators import permission_required@permission_required('front.view_article')
def my_view(request):...

注意: 如果需要校验多个权限,可以在permission_required中传入一个权限列表。

视图装饰器:link

分组

可以通过定义一个分组有什么权限,然后分组中加入多个用户,统一管理分组中用户的权限。
使用的是django.contrib.auth.models.Group模型, 每个用户组拥有id和name两个字段,该模型在数据库被映射为auth_group数据表。

分组操作

  1. 创建分组:

    Group.objects.create(name="运维")
    

  1. 分组上添加权限:

    使用group.permissions.set(permissions)一次添加多个权限
    使用group.permissions.add(permission1,permission2…)一个个添加权限

group = Group.objects.first()
content_type = ContentType.objects.get_for_model(Article)
permissions = Permission.objects.filter(content_type=content_type)
group.permissions.set(permissions)

  1. 分组上删除权限:
group.permissions.remove()
  1. 分组上清除所有权限:
group.permissions.clear()
  1. 分组添加用户:
group = Group.objects.first()
user = User.objects.get(pk=2)
user.groups.add(group)
user.save()

  1. 获取用户所属组的权限:
user.get_group_permissions()
  1. 判断用户是否有权限:
    会先判断用户是否有权限,再判断用户组是否有权限。
user.has_perm("权限")user.has_perms(["权限1", "权限2"])

django 验证和授权系统相关推荐

  1. ASP.NET Core:使用IdentityServer构建可靠的身份验证和授权系统

    目录 OAuth 2.0到底是什么? 为什么使用OpenID Connect? 向IdentityServer打个招呼!

  2. 乐抖网络验证授权系统PHP网站源码附带搭建教程

    乐抖网络验证授权系统PHP网站源码附带搭建教程 ☑️ 编号:ym505 ☑️ 品牌:无 ☑️ 语言:php ☑️ 大小:21.6MB ☑️ 类型:网络验证授权系统 ☑️ 支持:pc+wap

  3. php产品授权系统使用说明,2017最新PHP产品授权验证系统 v2.6.8

    PHP授权系统使用 配置conf/config.php 文件 $db_server='localhost'; $db_user='root'; //数据库用户名 $db_password='root' ...

  4. php卡密验证源码防破解抓包,PHP授权系统v2.7.0定制版 带卡密自助授权功能盗版检测一键更新...

    演示地址:如有演示站请以演示为准,无演示站以截图为准,源码太多服务器有限,无法搭建所有源码演示站,请谅解! 新手购买指导:1.在本站注册账号 丨 2.登录已注册账号充值源码所需金币 丨 3.登录账号下 ...

  5. Django默认用户认证系统和用户模型类

    Django默认用户认证系统和用户模型类 1.Django默认用户认证系统 Django自带用户认证系统 Django认证系统位置 Django认证系统同时处理认证和授权 Django认证系统包含的内 ...

  6. .NET Core微服务之基于Ocelot+IdentityServer实现统一验证与授权

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.案例结构总览 这里,假设我们有两个客户端(一个Web网站,一个移动App),他们要使用系统,需要通过API网关(这里API网关始终作为 ...

  7. django(权限、认证)系统—— 基于Authentication backends定制

    django(权限.认证)系统-- 基于Authentication backends定制 在这篇文章中,我们进行最后关于DjangoPermission系统的探讨,来谈谈关于Permission系统 ...

  8. Authentication vs. Authorization 验证与授权[整理]

    Authentication vs. Authorization 验证与授权 Authentication vs. Authorization 验证与授权 It is important to cla ...

  9. iis授权mysql验证_ASP.NET Web API身份验证和授权

    本文是作者所理解和翻译的内容. 这篇文章包括两部分:身份验证和授权. 身份验证用来确定一个用户的身份.例如,Alice用她的用户名和密码登陆系统,服务器用她的用户名和密码来确定她的身份. 授权是判断一 ...

最新文章

  1. ajax局部刷新后,如何让局部中的百度分享重新加载
  2. i2c hid 触摸板不能用_I2C 总线协议初探 - STM32 I2C 接口外设学习笔记
  3. 狮山路将装上“智慧大脑”
  4. PyQt4布局管理——绝对定位方式
  5. linux下找不到libc 库,Linux-覆盖libc open()库函数
  6. javaScript学习笔记之运算符
  7. Python 多版本共存问题 2
  8. 股票涨停之后该不该卖?
  9. css滤镜使文字变3D效果
  10. 谷歌浏览器无法登录账号
  11. 《搭建你的数字积木 数字电路与逻辑设计》(1)
  12. 前后端数据交互(八)——请求方法 GET 和 POST 区别
  13. 净推荐值NPS(Net Promoter Score)
  14. java时钟指针_时钟 走动 一个应用线程实现指针运动的指针时钟程序 联合开发网 - pudn.com...
  15. SOEM 源码解析 ecx_LRD
  16. 有什么好的论文查重软件?两分钟让你知道
  17. python函数文档说明调用方式_调用函数方法
  18. 完全平方数:若一个整数n能表示成某个整数m的平方的形式,则称这个数为完全平方数。写一个程序判断输入的整数是不是完全平方数。
  19. CTF之Bugku 游戏过关
  20. 导数、偏导数、方向导数、梯度、梯度下降

热门文章

  1. 菜鸟教程中——PHP测验
  2. 下载的小说是PDF文件,不能导入到小说阅读器里怎么办?
  3. python12306买票_使用 py12306 购票
  4. 实时数仓之 Kappa 架构与 Lambda 架构(建议收藏!)
  5. [论文写作]论文查重——如何选择查重系统
  6. 盛迈坤电商:拼多多开店需要掌握的开店基础
  7. 150句经典语录~!
  8. 监控概述 、 Zabbix基础 、 Zabbix监控服案例
  9. Unreal 4 C++开发,获取序列器上物体播放的自身音轨上的语音
  10. 软件工程精品课程--清华大学