#permissions.py
from django.core.urlresolvers import resolve #将url反解为url_name from django.shortcuts import render,redirect from django.conf import settings class CP(object): def __init__(self,perm_dict={}): #默认没有任何权限 self.perm_dict = perm_dict def check_permssion(self,func): #该装饰视图逻辑,检查权限 def inner(*args, **kwargs): if self.perm_check(*args, **kwargs): return func(*args, **kwargs) return render(args[0], '403页面.htm') #403自己定制 return inner def perm_check(self,*args, **kwargs): #干活的方法 request = args[0] # request if request.user.is_authenticated(): # 用户未认证先登录 if request.user.is_superuser: return True current_url_name = resolve(request.path_info).url_name # 当前访问的url的name值 status = False for k, v in self.perm_dict.items(): # 循环权限字典 if request.user.has_perm('%s.%s' % (k.split('_')[0], k)): if current_url_name == v[0]: # 判断当前name是否在权限中 if request.method == v[1]: # 判断用户在该视图中的请求方法 data_for_method = getattr(request, v[1]) args_status = True for item in v[2]: if not data_for_method.get(item): args_status = False break if args_status: kwargs_status = True for v_name, v_value in v[3].items(): if data_for_method.get(v_name) != str(v_value): kwargs_status = False break if kwargs_status: if len(v) == 5: return True if v[4](request) else False #传入request,调用定制函数 return True return status return redirect(settings.LOGIN_URL) #重定向可自己决定 permssion = CP()
两个不通用的地方:403页面 和 重定向
流程:
1、逻辑代码如上,使用单例模式;通过装饰器检查访问视图函数的权限
2、用户自定义权限字典
from permissions import permission
def check(request): #定制过滤函数
pass
perm_dict = {
权限名:[ url_name,请求method,[ 过滤内容名 ],{ 过滤具体内容 },可选的定制函数名 ],
...
}
permssion.perm_dict=perm_dict
- 权限名(字符串):应用名_会意命名,下划线后用url_name即可;注意应用名的选取
- url_name(字符串):url后的name值
- 方法(字符串):GET或POST
- [ 过滤内容名 ]:前端GET提交的内容,url中输入的,或其它。url中?后内容
- { 过滤具体内容 }:键值对形式精确过滤
- 可选的定制函数名:可选,只写函数名,必须传入一个位置参数,该参数当作请求的request使用,最终返回True或False
权限规则:
- perm_dict 不定制,则没有任何权限,除非是超级用户
- 权限列表中前两个若有空字符串,则没有该权限;后三个若有空则表示通过
3、装饰视图类或视图函数
- 类:参考django装饰器一节装饰器的用法
- 函数:
from .permissions import permssion @permssion.check_permssion
def index(request):
pass
4、models.py中的UserProfile类(取代django默认的auth.user)
class UserProfile(AbstractBaseUser,PermissionsMixin): ''' is_active和is_staff同时为True才能登录 ''' email = models.EmailField( verbose_name='email address', max_length=255, unique=True, ) name = models.CharField(verbose_name='姓名', max_length=64) role = models.ManyToManyField('Role', blank=True) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=True) objects = UserProfileManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['name'] def get_full_name(self): # The user is identified by their email address return self.email def get_short_name(self): # The user is identified by their email address return self.email def __str__(self): # __unicode__ on Python 2 return self.email class Meta: verbose_name = '用户信息表' verbose_name_plural = verbose_name #权限 permissions = ( ('crm_myadmin_index','myadmin的首页'), ('crm_app_model_obj_change','表修改'), ('crm_app_model_obj_list','查看表记录列表'), ('crm_app_model_obj_change_save','表修改并保存') )
如上:权限元组中第一项即我们定义的权限名,第二项是说明
最后:makemigrations,migrate
现在,在后台就能赋予用户我们自定制的权限了。(删除权限名须在数据库中删除)