django 验证和授权系统
django 验证和授权系统
- 验证和授权概述
- 使用授权系统
- INSTALLED_APPS
- 中间件
- User模型
- 字段
- User模型的基本用法
- 创建用户
- 创建超级用户
- 修改密码
- 登录验证:
- 扩展用户模型
- 设置Proxy模型
- 一对一外键:
- 继承AbstractUser
- 自定义User
- 自定义UserManager
- 修改authenticate的username校验字段
- 继承自AbstractBaseUser模型
- 外键使用注意事项
- 登录、注销和登录限制
- 登录
- 注销
- 登录限制
- 装饰器登录限制
- 中间件校验登录
- 权限
- 通过定义模型添加权限
- 通过代码添加权限
- 用户与权限管理
- 权限限定装饰器
- 分组
- 分组操作
验证和授权概述
Django有一个内置的授权系统,用来处理用户、分组、权限以及基于cookie的会话系统。
Django的授权系统包括验证和授权两个部分,验证是验证这个用户是否是他声称的人(比如用户名和密码验证,角色验证),授权是给与他相应的权限。
Django内置的权限系统包括以下方面:
- 用户。
- 权限。
- 分组。
- 一个可以配置的密码哈希系统。
- 一个可插拔的后台管理系统。
使用授权系统
默认中创建完一个django项目后,其实就已经集成了授权系统。授权系统相关的配置如下:
INSTALLED_APPS
- django.contrib.auth:包含了一个核心授权框架,以及大部分的模型定义。
- django.contrib.contenttypes:Content Type系统,可以用来关联模型和权限。
中间件
- SessionMiddleware:用来管理session。
- AuthenticationMiddleware:用来处理和当前session相关联的用户。
User模型
User模型是这个框架的核心部分。完整的路径是在django.contrib.auth.models.User。
User对象包含以下属性:
字段
内置的User模型拥有以下的字段:
- username: 用户名。150个字符以内。可以包含数字和英文字符,以及_、@、+、.和-字符。不能为空,且必须唯一!
- first_name:歪果仁的first_name,在30个字符以内。可以为空。
- last_name:歪果仁的last_name,在150个字符以内。可以为空。
- email:邮箱。可以为空。
- password:密码。经过哈希过后的密码。
- groups:分组。一个用户可以属于多个分组,一个分组可以拥有多个用户。groups这个字段是跟Group的一个多对多的关系。
- user_permissions:权限。一个用户可以拥有多个权限,一个权限可以被多个用户所有用。和Permission属于一种多对多的关系。
- is_staff:是否可以进入到admin的站点。代表是否是员工。
- is_active:是否是可用的。对于一些想要删除账号的数据,我们设置这个值为False就可以了,而不是真正的从数据库中删除。
- is_superuser:是否是超级管理员。如果是超级管理员,那么拥有整个网站的所有权限。
- last_login:上次登录的时间。
- 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
- 自定义User模型,继承自AbstractUser,新增字段;
- 修改settings.py中的AUTH_USER_MODEL;
- 映射数据库表(这种方式因为破坏了原来User模型的表结构,所以必须要在第一次migrate前就先定义好)。
自定义UserManager
如下图,create_user需要传入username,email,password。如果实际需求是通过telephone和password创建用户,就需要自定义UserManager。
- 自定义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)
- 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模型
- 定义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
在settings.py中设置AUTH_USER_MODEL: app_name.model:
映射到数据库:
创建user:
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进行登录。
- django的login其实也是在登录成功后,cookie中设置了sessionid。
- 正常情况下login接口不需要限制csrf_token,所以这里对LoginView过滤了Csrf校验。
- 如果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)
- 登录成功后,cookie中会有csrftoken和seesionid。
注销
注销、退出登录可以通过django.contrib.auth.logout来实现。它会清理掉这个用户的session数据。
如果在未登录的情况下访问logout会报403。
登录限制
有时候,某个视图函数是需要经过登录后才能访问的,比如logout接口。
有两种实现方法:
- 通过django.contrib.auth.decorators.login_required装饰器来实现。
- 通过中间件校验用户是否登录。
装饰器登录限制
示例代码如下:
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模型和权限之间的管理,可以通过以下几种方式来管理:
- 设置权限的列表:user.user_permissions.set(permission_list)。
清除所有权限:user.user_permissions.clear()。
一个个添加权限:myuser.user_permissions.add(permission, permission,…)。
一个个删除权限:myuser.user_permissions.remove(permission, permission,…)。
判断是否拥有某个权限:myuser.has_perm(’<app_name>.’),权限参数是一个字符串,格式是app_name.codename。
如下:pk=2的user只有show权限,没有add权限,通过has_perm可以进行判断。
注意:超级用户拥有所有权限。
- 获取用户所有的权限: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数据表。
分组操作
- 创建分组:
Group.objects.create(name="运维")
分组上添加权限:
使用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)
- 分组上删除权限:
group.permissions.remove()
- 分组上清除所有权限:
group.permissions.clear()
- 分组添加用户:
group = Group.objects.first()
user = User.objects.get(pk=2)
user.groups.add(group)
user.save()
- 获取用户所属组的权限:
user.get_group_permissions()
- 判断用户是否有权限:
会先判断用户是否有权限,再判断用户组是否有权限。
user.has_perm("权限")user.has_perms(["权限1", "权限2"])
django 验证和授权系统相关推荐
- ASP.NET Core:使用IdentityServer构建可靠的身份验证和授权系统
目录 OAuth 2.0到底是什么? 为什么使用OpenID Connect? 向IdentityServer打个招呼!
- 乐抖网络验证授权系统PHP网站源码附带搭建教程
乐抖网络验证授权系统PHP网站源码附带搭建教程 ☑️ 编号:ym505 ☑️ 品牌:无 ☑️ 语言:php ☑️ 大小:21.6MB ☑️ 类型:网络验证授权系统 ☑️ 支持:pc+wap
- php产品授权系统使用说明,2017最新PHP产品授权验证系统 v2.6.8
PHP授权系统使用 配置conf/config.php 文件 $db_server='localhost'; $db_user='root'; //数据库用户名 $db_password='root' ...
- php卡密验证源码防破解抓包,PHP授权系统v2.7.0定制版 带卡密自助授权功能盗版检测一键更新...
演示地址:如有演示站请以演示为准,无演示站以截图为准,源码太多服务器有限,无法搭建所有源码演示站,请谅解! 新手购买指导:1.在本站注册账号 丨 2.登录已注册账号充值源码所需金币 丨 3.登录账号下 ...
- Django默认用户认证系统和用户模型类
Django默认用户认证系统和用户模型类 1.Django默认用户认证系统 Django自带用户认证系统 Django认证系统位置 Django认证系统同时处理认证和授权 Django认证系统包含的内 ...
- .NET Core微服务之基于Ocelot+IdentityServer实现统一验证与授权
Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.案例结构总览 这里,假设我们有两个客户端(一个Web网站,一个移动App),他们要使用系统,需要通过API网关(这里API网关始终作为 ...
- django(权限、认证)系统—— 基于Authentication backends定制
django(权限.认证)系统-- 基于Authentication backends定制 在这篇文章中,我们进行最后关于DjangoPermission系统的探讨,来谈谈关于Permission系统 ...
- Authentication vs. Authorization 验证与授权[整理]
Authentication vs. Authorization 验证与授权 Authentication vs. Authorization 验证与授权 It is important to cla ...
- iis授权mysql验证_ASP.NET Web API身份验证和授权
本文是作者所理解和翻译的内容. 这篇文章包括两部分:身份验证和授权. 身份验证用来确定一个用户的身份.例如,Alice用她的用户名和密码登陆系统,服务器用她的用户名和密码来确定她的身份. 授权是判断一 ...
最新文章
- ajax局部刷新后,如何让局部中的百度分享重新加载
- i2c hid 触摸板不能用_I2C 总线协议初探 - STM32 I2C 接口外设学习笔记
- 狮山路将装上“智慧大脑”
- PyQt4布局管理——绝对定位方式
- linux下找不到libc 库,Linux-覆盖libc open()库函数
- javaScript学习笔记之运算符
- Python 多版本共存问题 2
- 股票涨停之后该不该卖?
- css滤镜使文字变3D效果
- 谷歌浏览器无法登录账号
- 《搭建你的数字积木 数字电路与逻辑设计》(1)
- 前后端数据交互(八)——请求方法 GET 和 POST 区别
- 净推荐值NPS(Net Promoter Score)
- java时钟指针_时钟 走动 一个应用线程实现指针运动的指针时钟程序 联合开发网 - pudn.com...
- SOEM 源码解析 ecx_LRD
- 有什么好的论文查重软件?两分钟让你知道
- python函数文档说明调用方式_调用函数方法
- 完全平方数:若一个整数n能表示成某个整数m的平方的形式,则称这个数为完全平方数。写一个程序判断输入的整数是不是完全平方数。
- CTF之Bugku 游戏过关
- 导数、偏导数、方向导数、梯度、梯度下降