基於django內置的權限管理系統寫一套自己的權限管理
阿新 • • 發佈:2017-12-22
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內置的權限管理系統寫一套自己的權限管理