当前位置:   article > 正文

django rest framwork用户权限设计和Authentication用户认证?_django tokenobtainpairview

django tokenobtainpairview

为什么要在业务中实现用户权限管理?

        在B/S系统中,浏览器是每一台计算机都已具备的,如果不建立一个完整的权限检测,那么一个"非法用户"很可能通过浏览器轻易访问到B/S系统中的所有功能。因此B/S系统业务中都需要一个或多个权限系统来实现访问权限检测,让经过授权的用户可以正常合法的使用已授权功能,而对那些未授权的“非法用户”会将他们彻底的“拒之门外”。

01 需求陈述

  • 不同职责的人,对于系统操作权限是不同的。

  • 根据“组”进行权限分配,将权限一致的人员编入同一组,然后对改组进行权限分配。

  • 权限管理系统应该是可扩展的。它应该可以加入到任何带有权限管理的系统中。就像组件一样可以不断的重用,而不是每开发一套管理系统,就要针对权限管理部分进行重新开发。

  • 基于django rest_framework设计登录身份token认证、权限功能设计和实现等。

在navicat中ER图标中,权限表、角色表、用户表之间是多不多的关系。

图片

02 用户权限表设计

  1. from django.db import models
  2. from django.contrib.auth.models import AbstractUser
  3. class Position(models.Model):
  4. """
  5. 职位/岗位
  6. """
  7. name = models.CharField('名称', max_length=32, unique=True)
  8. description = models.CharField('描述', max_length=50, blank=True, null=True)
  9. class Meta:
  10. verbose_name = '职位/岗位'
  11. verbose_name_plural = verbose_name
  12. def __str__(self):
  13. return self.name
  14. class Organization(models.Model):
  15. """
  16. 组织架构
  17. """
  18. organization_type_choices = (
  19. ('公司', '公司'),
  20. ('部门', '部门')
  21. )
  22. name = models.CharField('名称', max_length=60)
  23. type = models.CharField('类型', max_length=20,
  24. choices=organization_type_choices, default='部门')
  25. parent = models.ForeignKey('self', null=True, blank=True,
  26. on_delete=models.SET_NULL, verbose_name='父')
  27. class Meta:
  28. verbose_name = '组织架构'
  29. verbose_name_plural = verbose_name
  30. def __str__(self):
  31. return self.name
  32. class Permission(models.Model):
  33. """
  34. 功能权限:目录,菜单,接口
  35. """
  36. menu_type_choices = (
  37. ('目录', '目录'),
  38. ('菜单', '菜单'),
  39. ('接口', '接口')
  40. )
  41. name = models.CharField('名称', max_length=30)
  42. type = models.CharField('类型', max_length=20, choices=menu_type_choices, default='接口')
  43. is_frame = models.BooleanField('外部链接', default=False)
  44. sort = models.IntegerField('排序标记', default=1)
  45. parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='父')
  46. method = models.CharField('方法/代号', max_length=50,unique=True, null=True, blank=True)
  47. def __str__(self):
  48. return self.name
  49. class Meta:
  50. verbose_name = '功能权限表'
  51. verbose_name_plural = verbose_name
  52. ordering = ['sort']
  53. # 用户角色表
  54. class Role(models.Model):
  55. name = models.CharField('角色', max_length=32, unique=True)
  56. perms = models.ManyToManyField(Permission, blank=True, verbose_name='功能权限')
  57. depts = models.ManyToManyField(Organization, blank=True, verbose_name='权限范围')
  58. description = models.CharField('描述', max_length=50, blank=True, null=True)
  59. class Meta:
  60. verbose_name = '角色'
  61. verbose_name_plural = verbose_name
  62. def __str__(self):
  63. return self.name
  64. # 用户表
  65. class User(AbstractUser):
  66. name = models.CharField('姓名', max_length=20, null=True, blank=True)
  67. phone = models.CharField('手机号', max_length=11, null=True, blank=True, unique=True)
  68. avatar = models.CharField('头像', default='/media/default/avatar.png', max_length=100, null=True, blank=True)
  69. superior = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='上级主管')
  70. roles = models.ManyToManyField(Role, blank=True, verbose_name='角色')
  71. position = models.ManyToManyField(Position, blank=True, verbose_name='岗位')
  72. dept = models.ForeignKey(
  73. Organization, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='组织')
  74. class Meta:
  75. verbose_name = '用户信息'
  76. verbose_name_plural = verbose_name
  77. ordering = ['id']
  78. def __str__(self):
  79. return self.username

03 修改配置和权限代码

修改settings配置

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'rest_framework',
  9. 'apps.system'
  10. ]
  11. # JWT设置
  12. SIMPLE_JWT = {
  13. 'REFRESH_TOKEN_LIFETIME': timedelta(minutes=1),
  14. 'ACCESS_TOKEN_LIFETIME': timedelta(days=10), # 配置token过期时间
  15. 'ROTATE_REFRESH_TOKENS': True,
  16. }
  17. # 自定义认证后台(Backend)
  18. AUTH_USER_MODEL = 'system.User'
  19. AUTHENTICATION_BACKENDS = (
  20. 'utils.authentication.CustomBackend',
  21. )
  22. REST_FRAMEWORK = {
  23. 'DEFAULT_AUTHENTICATION_CLASSES': [
  24. 'rest_framework_simplejwt.authentication.JWTAuthentication',
  25. ],
  26. 'DEFAULT_FILTER_BACKENDS': [
  27. 'django_filters.rest_framework.DjangoFilterBackend',
  28. ],
  29. }

用户身份认证authentication.py

  1. from django.contrib.auth.backends import ModelBackend
  2. from django.db.models import Q
  3. from django.contrib.auth import get_user_model
  4. UserModel = get_user_model()
  5. class CustomBackend(ModelBackend):
  6. def authenticate(self, request, username=None, password=None, **kwargs):
  7. if username is None:
  8. username = kwargs.get(UserModel.USERNAME_FIELD)
  9. if username is None or password is None:
  10. return
  11. try:
  12. user = UserModel._default_manager.get(
  13. Q(username=username) | Q(phone=username) | Q(email=username))
  14. except UserModel.DoesNotExist:
  15. # Run the default password hasher once to reduce the timing
  16. # difference between an existing and a nonexistent user (#20760).
  17. UserModel().set_password(password)
  18. else:
  19. if user.check_password(password) and self.user_can_authenticate(user):
  20. return user

自定义权限验证permission.py

  1. from django.core.cache import cache
  2. from rest_framework.permissions import BasePermission
  3. from apps.system.models import Permission
  4. def get_permission_list(user):
  5. """
  6. 获取权限列表,可用redis存取
  7. """
  8. if user.is_superuser:
  9. perms_list = ['admin']
  10. else:
  11. perms = Permission.objects.none()
  12. roles = user.roles.all()
  13. if roles:
  14. for i in roles:
  15. perms = perms | i.perms.all()
  16. perms_list = perms.values_list('method', flat=True)
  17. perms_list = list(set(perms_list))
  18. cache.set(user.username + '__perms', perms_list, 60 * 60)
  19. return perms_list
  20. class RbacPermission(BasePermission):
  21. """
  22. 基于角色的权限校验类
  23. """
  24. def has_permission(self, request, view):
  25. """
  26. 权限校验逻辑
  27. :param request:
  28. :param view: 视图对象
  29. :return:
  30. """
  31. path = request._request.path # client访问的api接口名
  32. perms = get_permission_list(request.user) # list
  33. if'admin'in perms:
  34. return True
  35. if perms:
  36. if path in perms:
  37. return True
  38. else:
  39. return False
  40. else:
  41. return False
  42. def has_object_permission(self, request, view, obj):
  43. """
  44. Return `True` if permission is granted, `False` otherwise.
  45. """
  46. ifnot request.user:
  47. return False
  48. return True

单个视图权限控制views.py

  1. from .models import Category
  2. from utils.permission import RbacPermission
  3. class CategoryViewSet(ModelViewSet):
  4. permission_classes = [RbacPermission]
  5. queryset = Category.objects.all()
  6. serializer_class = CategoryListSerializer
  7. search_fields = ['name']

全局权限设置

  1. REST_FRAMEWORK = {
  2. 'DEFAULT_AUTHENTICATION_CLASSES': [
  3. 'rest_framework_simplejwt.authentication.JWTAuthentication',
  4. ],
  5. 'DEFAULT_PERMISSION_CLASSES': [
  6. 'rest_framework.permissions.IsAuthenticated',
  7. 'apps.system.permission.RbacPermission'
  8. ],
  9. 'DEFAULT_FILTER_BACKENDS': [
  10. 'django_filters.rest_framework.DjangoFilterBackend',
  11. ],
  12. }

登录token获取

  1. from django.contrib import admin
  2. from django.urls import path, include
  3. from rest_framework_simplejwt.views import (
  4. TokenObtainPairView,
  5. TokenRefreshView,
  6. )
  7. from rest_framework import routers
  8. from apps.system.views import LogoutView
  9. router = routers.DefaultRouter()
  10. urlpatterns = [
  11. path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
  12. path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
  13. path('token/black/', LogoutView.as_view(), name='token_black'),
  14. path('system/', include('apps.system.urls')),
  15. path('blog/', include('apps.blog.urls')),
  16. ]

postman测试登录接口

图片

用户管理列表

图片

用户张三的权限列表

图片

用户的权限分配

图片

权限菜单配置

图片

        权限系统可以说是整个系统中最基础,同时也可以很复杂的,在实际项目中,会遇到多个系统,多个用户类型,多个使用场景,这就需要具体问题具体分析,但最核心的RBAC模型是不变的,我们可以在其基础上进行扩展来满足需求。最后,如果您觉得这篇文章对您有帮助,可以点个赞,谢谢支持!

参考

https://github.com/caoqianming/django-vue-admin

希望对大家有所帮助有问题可以联系作者。感兴趣的可以关注作者微信公众号:程序员9527

图片

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/944361
推荐阅读
相关标签
  

闽ICP备14008679号