一。权限六表。

  一般在django中,基于用户权限访问控制的认证是RBAC(Role-Based Access Control)

  还有一些基于auth的认证规则。

  Django框架采用的是RBAC认证规则,RBAC认证规则通常会分为 三表规则、五表规则,Django采用的是六表规则。

  这些表在model创建的时候需要继承类:AbstractUser

  三表:用户表、角色表、权限表。

  五表:用户表、角色表、权限表、用户角色关系表、角色权限关系表。

  六表:用户表、角色表、权限表、用户角色关系表、角色权限关系表、用户权限关系表。

  用户表与角色表之间是多对多,

  角色表与权限表之间是多对多,

  用户表与权限表之间是多对多。

  表与表之间的使用如下:

# 用户表:角色groups,权限user_permissions
# 角色表:用户user_set,权限permissions
# 权限表:用户user_set,角色group_set

  注意:如果自定义的User表创建后,另一个项目创建原生User完成数据库迁移的时候可能会失败,可以有以下解决方法:

  1)卸载Django重新装。

  2)将django.contrib下面的admin、auth下的数据库迁移记录文件清空。

二。三大认证的源码分析。

  首先需要从APIview中的dispatch来分发任务:

    dispath(self, request, *args, **kwargs)

  再从dispatch中的initial进入三大认证

self.initial(request, *args, **kwargs) #进入三大认证

  三大认证分别是以下认证:

  1.校验用户:

    # 认证组件:校验用户 - 游客、合法用户、非法用户
# 游客:代表校验通过,直接进入下一步校验(权限校验)
# 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
# 非法用户:代表校验失败,抛出异常,返回403权限异常结果
self.perform_authentication(request)

  2。校验权限。

    # 权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色
# 认证通过:可以进入下一步校验(频率认证)
# 认证失败:抛出异常,返回403权限异常结果
self.check_permissions(request)

  3.频率校验。

    # 频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、
      频率周期时间(s、m、h)、频率的次数(3/s)
# 没有达到限次:正常访问接口
# 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
self.check_throttles(request)

三。用户认证

  在用户认证的过程中,需要注意的是request.user是获取user的get方法,还有self代表的是request。

  1.找到dispatch中的三大认证函数入口。

  2.第一个认证组件中指向了request中的user,get方法。

  3.request中检测错误,如果没有找到user则开始认证,否则返回该用户。获取认证信息。

  4.遍历早就封装在request中的authenticators。其中包括了所有的settting中的配置的认证类。遍历所有该类生成的对象,运行其中的authenticate(自定义的关键函数)。

  5。所有的认证类都继承自baseauthentication,和其中的authenticate

    # 做认证
def _authenticate(self):
# 遍历拿到一个个认证器,进行认证
# self.authenticators配置的一堆认证类产生的认证类对象组成的 list
for authenticator in self.authenticators:
try:
# 认证器(对象)调用认证方法authenticate
            (认证类对象self, request请求对象)
# 返回值:登陆的用户与认证的信息组成的 tuple
# 该方法被try包裹,代表该方法会抛异常,抛异常就代表认证失败
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise # 返回值的处理
if user_auth_tuple is not None:
self._authenticator = authenticator
# 如何有返回值,就将 登陆用户 与 登陆认证 分别
            保存到 request.user、request.auth
self.user, self.auth = user_auth_tuple
return
# 如果返回值user_auth_tuple为空,代表认证通过,但是没有 登陆用户 与
          登陆认证信息,代表游客
self._not_authenticated()

四。自定义认证类。

  在自定义认证类时,需要可以进行如下操作:

"""
1) 创建继承BaseAuthentication的认证类
2) 实现authenticate方法
3) 实现体根据认证规则 确定游客、非法用户、合法用户
4) 进行全局或局部配置 认证规则
i.没有认证信息返回None(游客)
ii.有认证信息认证失败抛异常(非法用户)
iii.有认证信息认证成功返回用户与认证信息元组(合法用户)
"""

  自定义如下:

# 自定义认证类

# 1)继承BaseAuthentication类
# 2)重新authenticate(self, request)方法,自定义认证规则
# 3)认证规则基于的条件:
# 没有认证信息返回None(游客)
# 有认证信息认证失败抛异常(非法用户)
# 有认证信息认证成功返回用户与认证信息元组(合法用户)
# 4)完全视图类的全局(settings文件中)或局部(确切的视图类)配置
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from . import models
class MyAuthentication(BaseAuthentication):
"""
同前台请求头拿认证信息auth(获取认证的字段要与前台约定)
没有auth是游客,返回None
有auth进行校验
失败是非法用户,抛出异常
成功是合法用户,返回 (用户, 认证信息)
"""
def authenticate(self, request):
# 前台在请求头携带认证信息,
# 且默认规范用 Authorization 字段携带认证信息,
# 后台固定在请求对象的META字段中 HTTP_AUTHORIZATION 获取
auth = request.META.get('HTTP_AUTHORIZATION', None) # 处理游客
if auth is None:
return None # 设置一下认证字段小规则(两段式):"auth 认证字符串"
auth_list = auth.split() # 校验合法还是非法用户
if not (len(auth_list) == 2 and auth_list[0].lower() == 'auth'):
raise AuthenticationFailed('认证信息有误,非法用户') # 合法的用户还需要从auth_list[1]中解析出来
# 注:假设一种情况,信息为abc.123.xyz,就可以解析出admin用户;实际开发,该逻辑一定是校验用户的正常逻辑
if auth_list[1] != 'abc.123.xyz': # 校验失败
raise AuthenticationFailed('用户校验失败,非法用户') user = models.User.objects.filter(username='admin').first() if not user:
raise AuthenticationFailed('用户数据有误,非法用户')
return (user, None)

utils/authentications.py

五。权限认证。

  权限认证中必须要通过用户认证,而且其中user必须要有值。

4) 权限组件
self.check_permissions(request)
认证细则:
def check_permissions(self, request):
# 遍历权限对象列表得到一个个权限对象(权限器),进行权限认证
for permission in self.get_permissions():
# 权限类一定有一个has_permission权限方法,用来做权限认证的
# 参数:权限对象self、请求对象request、视图类对象
# 返回值:有权限返回True,无权限返回False
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, 'message', None)
)

  系统权限类中,提供了如下的方法进行权限识别,这些方法可以在局部定义类方法进行配置:

"""
1)AllowAny:
认证规则全部返还True:return True
游客与登陆用户都有所有权限 2) IsAuthenticated:
认证规则必须有登陆的合法用户:
    return bool(request.user and request.user.is_authenticated)
游客没有任何权限,登陆用户才有权限 3) IsAdminUser:
认证规则必须是后台管理用户:
    return bool(request.user and request.user.is_staff)
游客没有任何权限,登陆用户才有权限 4) IsAuthenticatedOrReadOnly
认证规则必须是只读请求或是合法用户:
return bool(
request.method in SAFE_METHODS or
request.user and
request.user.is_authenticated
)
游客只读,合法用户无限制
""" # api/views.py
from rest_framework.permissions import IsAuthenticated
class TestAuthenticatedAPIView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, *args, **kwargs):
return APIResponse(0, 'test 登录才能访问的接口 ok') # 因为默认全局配置的权限类是AllowAny
# settings.py
REST_FRAMEWORK = {
# 权限类配置
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
],
}

六。自定义权限类。

  在自定义权限类时需要遵循以下方法:

"""
1) 创建继承BasePermission的权限类
2) 实现has_permission方法
3) 实现体根据权限规则 确定有无权限
4) 进行全局或局部配置 认证规则
i.满足设置的用户条件,代表有权限,返回True
ii.不满足设置的用户条件,代表有权限,返回False
"""

  自定义如下:

# utils/permissions.py
from rest_framework.permissions import BasePermission
from django.contrib.auth.models import Group
class MyPermission(BasePermission):
def has_permission(self, request, view):
# 只读接口判断
r1 = request.method in ('GET', 'HEAD', 'OPTIONS')
# group为有权限的分组
group = Group.objects.filter(name='管理员').first()
# groups为当前用户所属的所有分组
groups = request.user.groups.all()
r2 = group and groups
r3 = group in groups
# 读接口大家都有权限,写接口必须为指定分组下的登陆用户
return r1 or (r2 and r3) # 游客只读,登录用户只读,只有登录用户属于 管理员 分组,才可以增删改
from utils.permissions import MyPermission
class TestAdminOrReadOnlyAPIView(APIView):
permission_classes = [MyPermission]
# 所有用户都可以访问
def get(self, request, *args, **kwargs):
return APIResponse(0, '自定义读 OK')
# 必须是 自定义“管理员”分组 下的用户
def post(self, request, *args, **kwargs):
return APIResponse(0, '自定义写 OK')

utils/permissions.py

Role-Based Access Control

最新文章

  1. 免费薪资总额管控系统-JXHR2016
  2. 学习笔记:MySQL操作初步
  3. [51NOD1126]求递推序列的第n项(矩阵快速幂)
  4. PHP 各种函数
  5. Array.asList()注意
  6. HTML中如何添加日历插件(JQUERY)
  7. 快速搞定selenium grid分布式
  8. 基于Windows环境下cmd/编译器无法输入中文,显示中文乱码解决方案
  9. Aop实现SqlSugar自动事务
  10. python入门篇
  11. java 图片转base64字符串、base64字符串转图片
  12. Go之unsafe.Pointer && uintptr 类型
  13. Kivy 从memory 读取image
  14. beta冲刺随笔集
  15. python五十六课——正则表达式(常用函数之compile())
  16. Linux内核分析作业第七周
  17. Xcode dSYM 文件
  18. Jmeter Connect to Cassandra
  19. python第九课——while死循环
  20. 将项目托管到GitHub实现步骤

热门文章

  1. bps和pps
  2. Unity如何更改精灵中心点
  3. LG1131 「ZJOI2007」时态同步 树形DP
  4. 【洛谷5363】[SDOI2019] 移动金币(动态规划)
  5. Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3) E. Arson In Berland Forest 二分 前缀和
  6. 第04组 Alpha冲刺(1/4)
  7. Java连载42-this不能省略的情况、构造方法设置默认值的方法
  8. Python变量与内存管理
  9. Linux-Bash终端快捷键
  10. Kafka常见错误整理(不断更新中)