需求:權限模塊對各子系統擁有動態配置權限的能力,發現接口變化能力,權限認證能力等,因為各子系統相互獨立,
所以需要使用統一的認證 JWT。
1、使用Django DRF權限模塊,進行修改
1 import requests 2 from config import AUTHENTICATE_URL 3 from rest_framework import permissions 4 from rest_framework.exceptions import PermissionDenied, AuthenticationFailed 5 6 # URL(ViewSet) 權限配置 7 URL_PERMISSION = { 8 "pipelines": { 9 "test_pipeline": "account.dev_audit", 10 "list": "account.test_audit", 11 "create": "account.yw_audit", 12 "retrieve": "", 13 }, 14 # "sub_pipelines": { 15 # "test_pipeline": "account.dev_audit", 16 # "list": "account.test_audit", 17 # "create": "account.yw_audit", 18 # } 19 } 20 21 22 class LoginPermission(permissions.BasePermission): 23 """ 24 登錄驗證 25 """ 26 27 def has_permission(self, request, view): 28 # Read permissions are allowed to any request, 29 # so we'll always allow GET, HEAD or OPTIONS requests. 30 # print(request.method) 31 # if request.method == "POST": 32 # return False 33 # 34 # # 只有該snippet的所有者才允許寫權限。 35 # return False 36 37 token = request.META.get("HTTP_AUTHORIZATION", "").replace("JWT ", '') 38 data = requests.post(AUTHENTICATE_URL + "/api/account/verify/", json={"token": token}) 39 if data.status_code != 404: 40 raise AuthenticationFailed("登錄驗證失敗") 41 return True 42 43 44 class UrlPermission(permissions.BasePermission): 45 """ 46 URL 權限驗證 47 """ 48 49 def has_permission(self, request, view): 50 # Read permissions are allowed to any request, 51 # so we'll always allow GET, HEAD or OPTIONS requests. 52 # print(request.method) 53 # if request.method == "POST": 54 # return False 55 # 56 # # 只有該snippet的所有者才允許寫權限。 57 # return False 58 token = request.META.get("HTTP_AUTHORIZATION", "").replace("JWT ", '') 59 print("==========通過視圖的basename,action進行權限認證==========") 60 print(view.basename, view.action) 61 print("==========") 62 if view.basename in URL_PERMISSION.keys(): 63 if view.action in URL_PERMISSION[view.basename].keys(): 64 print(URL_PERMISSION[view.basename][view.action]) 65 data = requests.post(AUTHENTICATE_URL + "/api/account/verify/", 66 json={"token": token, "perm_code": URL_PERMISSION[view.basename][view.action]}) 67 if data.status_code != 404: 68 raise PermissionDenied("訪問權限不合法") 69 70 return True
2、設置權限全局生效
REST_FRAMEWORK = { # "DEFAULT_AUTHENTICATION_CLASSES": ["apps.permissions.Loginpermission", ] "DEFAULT_PERMISSION_CLASSES": [ "apps.permissions.LoginPermission", "apps.permissions.UrlPermission", ] }
如果需要局部權限,可以在相關視圖集(ViewSet)下增加自己的權限模塊
class PipelinesViewSet(BaseView): """ 流水線視圖 """ queryset = Pipelines.objects.filter(is_del=0).order_by("update_time") serializer_class = PipelinesSerializer filter_backends = (DjangoFilterBackend,) filter_fields = ('pipeline_name', 'pipeline_type') # permission_classes = () # 這里配置視圖權限 @action(methods=['post'], detail=True, permission_classes=[]) #這里配置接口權限 def test_pipeline(self, request, pk=None): """ 測試流水線接口 """ instance = self.get_object() serializer = self.get_serializer(instance) return Response(self.object_return(serializer.data))
3、權限系統統一獲取子系統接口,后期可以進行動態權限賦予
import coreapi # Initialize a client & load the schema document client = coreapi.Client() schema = client.get("http://127.0.0.1:8000/docs/") URL = [] # print(schema.data) for basename, actions in schema.data.items(): for action, atr in actions.links.items(): URL_dict = {} URL_dict["basename"] = basename URL_dict["action"] = action URL_dict["method"] = atr.action URL_dict["url"] = atr.url URL_dict["description"] = atr.description URL.append(URL_dict) for url in URL: print(url)
運行結果:這里收集視圖集中的base_name、action以及method,
對接口權限進行精確定位,不受url變化影響, 這里的url只做相關描述展示:
{'basename': 'pipelines', 'action': 'list', 'method': 'get', 'url': 'http://127.0.0.1:8000/apps/pipelines/', 'description': '流水線視圖'} {'basename': 'pipelines', 'action': 'create', 'method': 'post', 'url': 'http://127.0.0.1:8000/apps/pipelines/', 'description': '流水線視圖'} {'basename': 'pipelines', 'action': 'read', 'method': 'get', 'url': 'http://127.0.0.1:8000/apps/pipelines/{id}/', 'description': '流水線視圖'} {'basename': 'pipelines', 'action': 'update', 'method': 'put', 'url': 'http://127.0.0.1:8000/apps/pipelines/{id}/', 'description': '流水線視圖'} {'basename': 'pipelines', 'action': 'partial_update', 'method': 'patch', 'url': 'http://127.0.0.1:8000/apps/pipelines/{id}/', 'description': '流水線視圖'} {'basename': 'pipelines', 'action': 'delete', 'method': 'delete', 'url': 'http://127.0.0.1:8000/apps/pipelines/{id}/', 'description': '流水線視圖'} {'basename': 'pipelines', 'action': 'test_pipeline', 'method': 'post', 'url': 'http://127.0.0.1:8000/apps/pipelines/{id}/test_pipeline/', 'description': '測試流水線接口'} {'basename': 'urlcollections', 'action': 'list', 'method': 'get', 'url': 'http://127.0.0.1:8000/apps/urlcollections/', 'description': ''} {'basename': 'urlcollections', 'action': 'create', 'method': 'post', 'url': 'http://127.0.0.1:8000/apps/urlcollections/', 'description': ''}
前提:這里需要子系統開啟API接口文檔,通過接口文檔獲取接口詳情
from django.urls import path, include from rest_framework.documentation import include_docs_urls urlpatterns = [ # path('admin/', admin.site.urls), path('docs/', include_docs_urls(title='API文檔', authentication_classes=[], permission_classes=[])), path('apps/', include('apps.urls')), ]
以上,大概可以符合需求,URL可以讀取接口導入權限系統,動態分配
java 也有比較好的接口權限細化管理的方案,如apache shiro.
大神改進版 ,開源地址:https://gitee.com/tomsun28/bootshiro
還有的是casbin ,支持多種語言,github地址:https://github.com/casbin/pycasbin
但是這個也是針對於單個系統,如果需要對各個子系統進行接口權限控制,也是需要一番改造。