|
|
import json
|
|
|
import re
|
|
|
|
|
|
from django.conf import settings
|
|
|
from django_redis import get_redis_connection
|
|
|
from rest_framework.permissions import BasePermission
|
|
|
import logging
|
|
|
|
|
|
from ERP_5.utils.cache_permissions import cache_permissions_by_user
|
|
|
|
|
|
logger = logging.getLogger('my')
|
|
|
|
|
|
|
|
|
class RbacPermission(BasePermission):
|
|
|
"""
|
|
|
自定义权限认证
|
|
|
"""
|
|
|
|
|
|
def do_url(self, url):
|
|
|
"""
|
|
|
得到完整的访问URL
|
|
|
"""
|
|
|
base_api = settings.BASE_API
|
|
|
uri = '/' + base_api + '/' + url + '/'
|
|
|
return re.sub('/+', '/', uri) # 防止访问地址中出现重复的/,比如://users/hello/
|
|
|
|
|
|
def has_permission(self, request, view):
|
|
|
"""
|
|
|
判断是否有权限,该函数必须要重写
|
|
|
思路和步骤:
|
|
|
1、获取请求的URL,和请求方法method,user用户对象
|
|
|
2、判断是否白名单的url, 或者用户的角色是admin也直接放行
|
|
|
3、从redis中得到当前登录用户的所有权限
|
|
|
4、判断是否存在权限
|
|
|
"""
|
|
|
request_url = request.path # api/users/login/ == api/users/login/
|
|
|
request_method = request.method
|
|
|
logger.info(f'请求地址:{request_url}, 请求方法: {request_method}')
|
|
|
for safe_url in settings.WHITE_LIST:
|
|
|
if re.match(settings.REGEX_URL.format(url=safe_url), request_url):
|
|
|
# 白名单的url,直接返回
|
|
|
return True
|
|
|
user = request.user
|
|
|
role_name_list = user.roles.values_list('name', flat=True)
|
|
|
logger.info(role_name_list)
|
|
|
if 'admin' in role_name_list:
|
|
|
return True
|
|
|
|
|
|
redis_conn = get_redis_connection('default') # 获得默认redis库的连接
|
|
|
if not redis_conn.exists(f'user_{user.id}'): # redis中没有缓存权限数据
|
|
|
cache_permissions_by_user(user)
|
|
|
|
|
|
# 得到所有的权限中key,其中key是请求url地址
|
|
|
url_keys = redis_conn.hkeys(f'user_{user.id}')
|
|
|
for url_key in url_keys:
|
|
|
# 查看在redis中是否存在该接口对于的权限
|
|
|
if re.match(settings.REGEX_URL.format(url=self.do_url(url_key.decode())), request_url):
|
|
|
redis_key = url_key.decode() # redis中是字节数据
|
|
|
break
|
|
|
else: # 这行代码可以不加,如果严格规定权限。
|
|
|
return False
|
|
|
|
|
|
permissions = json.loads(redis_conn.hget(f'user_{user.id}', redis_key).decode())
|
|
|
method_hit = False # 同一接口配置不同权限验证
|
|
|
for permission in permissions:
|
|
|
if permission.get('method') == request_method:
|
|
|
method_hit = True
|
|
|
break
|
|
|
|
|
|
return method_hit
|