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