1. 程式人生 > >基於django內置的權限管理系統寫一套自己的權限管理

基於django內置的權限管理系統寫一套自己的權限管理

obj add bad args delet 拼接 turn cts 兒童

#基礎知識
#rest framwork 的內置admin的權限控制中,默認為每個model生成了3個權限: add update delete 
#將信息保存在內置的content_type表中,表中保存了model所在的app 和model的三個權限
#admin的權限管理系統由內置的三張表組成 user group permission  三張表之間的關系又由另外3張表來連接
#他們的關系如下圖



#利用內置權限管理定制自己所需要的權限系統的方法
#只需做一些稍微的修改,便可以使用內置的權限系統,為自己所用了

#1 寫自己的user表,繼承AbstractUser,可以添加額外的字段,但默認已經有了用戶名和密碼
class Manager(AbstractUser): mobile_number = models.CharField(max_length=20, verbose_name=手機號) #定制需要的登陸驗證方法,默認的登陸驗證是用戶名和密碼 class CustomBackend(ModelBackend): """ 定義用戶登錄方式(手機號/郵箱登錄) """ def authenticate(self, request, username=None, password=None, **kwargs): try
: manager = Manager.objects.get(Q(mobile_number=username) | Q(email=username)) if manager.check_password(password): return manager else: raise ValidationError(用戶名或密碼錯誤, code=status.HTTP_400_BAD_REQUEST) except Exception
as e: raise ValidationError(用戶名或密碼錯誤, code=status.HTTP_400_BAD_REQUEST) #由於默認只有增改刪3個權限,我們要為它添加一個查看的權限,為此我們要添加自定義權限 #在model中添加如下信息 class Kids(models.Model): class Meta: permissions = ( (view_kids_list, 查看兒童信息表), ) #為用戶分配權限 #檢驗用戶是否有的權限 class KidsViewSet() permission_classes = (permissions.DjangoModelPermissions,) #添加權限限制 def list(self, request, *args, **kwargs): user = request.user if user.has_perm(kids.view_kids_list): #‘app名.權限名’ return super(KidsViewSet, self).list(request, *args, **kwargs) else: data = {detail: 沒有權限} return Response(data, status=status.HTTP_403_FORBIDDEN) #模仿admin修改密碼 #加密以及解密方法 class ManagerPasswordSerializer(serializers.Serializer): #添加額外字段的方法 old_password = serializers.CharField(source=my_field) password = serializers.CharField(required=True) class Meta: model = Manager fields = __all__ class ManagerPasswordViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet): """ 用戶修改密碼接口 """ queryset = Manager.objects.all() versioning_class = URLPathVersioning serializer_class = serializers.ManagerPasswordSerializer def update(self, request, version, *args, **kwargs): data = request.data new_password = data[password] old_password = data[old_password] from django.contrib.auth.hashers import check_password, make_password #驗證舊密碼是否正確 username = request.user.username password = Manager.objects.filter(username=username).values(password) if check_password(old_password, password[0][password]): #修改為新密碼 Manager.objects.filter(username=username).update(password=make_password(new_password)) return Response(修改成功, status=status.HTTP_200_OK) else: return Response(密碼輸入錯誤, status=status.HTTP_400_BAD_REQUEST) #最後,只要給用戶分配了相應的權限,就可以輕松的擁有一套權限系統啦 #可以在用戶登陸時給用戶發送一個權限菜單 #思路是: #1 新建一個菜單表,存儲一級二級菜單的信息,每個對應content_type表中的每個model #2 用戶登陸時獲取用戶的權限信息(具體形式是對哪些model的什麽權限),在全部的權限(菜單表)中篩選出用戶對哪些model具有權限,再拼接出url, #3 按菜單表中的信息形成嵌套層級關系,最後返回給用戶菜單信息 class Menu(models.Model): """ 用戶權限菜單表 """ content_model = models.ForeignKey(ContentType, null=True) first_menu_name = models.CharField(max_length=100, null=True) second_menu_name = models.CharField(max_length=100, null=True) second_menu_parent = models.ForeignKey(Menu, null=True) second_menu_url = models.URLField(null=True) create_date = models.DateTimeField(verbose_name=申請日期, default=datetime.now, null=True) def __str__(self): return self.id class Meta: verbose_name = "菜單" verbose_name_plural = verbose_name def list(self, request, *args, **kwargs): # 獲取域名和版本 url = request.get_host() version = request.version # 用戶所有的model權限 permission_list = request.user.get_all_permissions() username = request.user.username user_model = set() for i in permission_list: model = i.split(_)[-1] user_model.add(model) user_model1 = list(user_model) first_info = Menu.objects.filter(content_model__model__in=user_model1, first_menu_name__isnull=False, second_menu_url__isnull=False).values(id, first_menu_name, second_menu_url) second_info = Menu.objects.filter(content_model__model__in=user_model1, second_menu_name__isnull=False, ).values(second_menu_name, second_menu_url, second_menu_parent_id) # 拼接完整url,替換原來的url for i in first_info: if not i[second_menu_url]: continue i[second_menu_url] = url + / + version + i[second_menu_url] for i in second_info: if not i[second_menu_url]: continue i[second_menu_url] = url + / + version + i[second_menu_url] # 形成嵌套關系 for i in first_info: i[child] = [] for j in second_info: if i[id] == j[second_menu_parent_id]: i[child].append(j) first_info = list(first_info) first_info.append({username: username}) return Response(first_info) #缺陷: 權限只能限制到表的級別,不能限制到操作action的級別

基於django內置的權限管理系統寫一套自己的權限管理