From 16b724bd4092575f578ef340674818f9aff56ab8 Mon Sep 17 00:00:00 2001 From: pycook Date: Wed, 4 Dec 2019 18:14:09 +0800 Subject: [PATCH] ACL: permission management [doing] --- api/lib/perm/acl/acl.py | 65 +++++----- api/lib/perm/acl/resource.py | 4 +- api/lib/perm/acl/role.py | 15 ++- api/lib/perm/acl/user.py | 22 +++- api/views/acl/resources.py | 3 +- api/views/acl/role.py | 3 +- ui/src/config/router.config.js | 8 +- ui/src/views/acl/module/permissionForm.vue | 2 +- ui/src/views/acl/module/resourceForm.vue | 42 ++---- ui/src/views/acl/module/resourcePermForm.vue | 116 ++--------------- .../acl/module/resourcePermManageForm.vue | 120 ++++++++++++++++++ ui/src/views/acl/module/resourceTypeForm.vue | 7 +- ui/src/views/acl/module/roleForm.vue | 70 ++++++++-- ui/src/views/acl/module/userForm.vue | 28 +++- ui/src/views/acl/permissions.vue | 2 +- ui/src/views/acl/resource_types.vue | 6 +- ui/src/views/acl/resources.vue | 89 ++++++++----- ui/src/views/acl/roles.vue | 34 ++--- ui/src/views/acl/users.vue | 51 +++----- 19 files changed, 396 insertions(+), 291 deletions(-) create mode 100644 ui/src/views/acl/module/resourcePermManageForm.vue diff --git a/api/lib/perm/acl/acl.py b/api/lib/perm/acl/acl.py index 7902b04..ea7c400 100644 --- a/api/lib/perm/acl/acl.py +++ b/api/lib/perm/acl/acl.py @@ -3,52 +3,47 @@ import functools import six - from flask import current_app, g, request from flask import session, abort -from api.extensions import cache - - -def get_access_token(): - return - - -class AccessTokenCache(object): - @classmethod - def get(cls): - if cache.get("AccessToken") is not None: - return cache.get("AccessToken") - - res = get_access_token() or "" - - cache.set("AccessToken", res, timeout=60 * 60) - return res - - @classmethod - def clean(cls): - cache.clear("AccessToken") +from api.lib.perm.acl.cache import AppCache +from api.models.acl import ResourceType +from api.models.acl import Resource +from api.lib.perm.acl.resource import ResourceCRUD class ACLManager(object): def __init__(self): - self.access_token = AccessTokenCache.get() - self.acl_session = dict(uid=session.get("uid"), - token=self.access_token) - self.user_info = session["acl"] if "acl" in session else {} + self.app_id = AppCache.get('cmdb') + if not self.app_id: + raise Exception("cmdb not in acl apps") + self.app_id = self.app_id.id def add_resource(self, name, resource_type_name=None): - pass + resource_type = ResourceType.get_by(name=resource_type_name, first=True, to_dict=False) + if resource_type: + return abort(400, "ResourceType <{0}> cannot be found".format(resource_type_name)) + + ResourceCRUD.add(name, resource_type.id, self.app_id) def grant_resource_to_role(self, name, role, resource_type_name=None): - pass + resource_type = ResourceType.get_by(name=resource_type_name, first=True, to_dict=False) + if resource_type: + return abort(400, "ResourceType <{0}> cannot be found".format(resource_type_name)) def del_resource(self, name, resource_type_name=None): - pass + resource_type = ResourceType.get_by(name=resource_type_name, first=True, to_dict=False) + if resource_type: + return abort(400, "ResourceType <{0}> cannot be found".format(resource_type_name)) - def get_user_info(self, username): - return dict() + resource = Resource.get_by(resource_type_id=resource_type.id, + app_id=self.app_id, + name=name, + first=True, + to_dict=False) + if resource: + ResourceCRUD.delete(resource.id) def get_resources(self, resource_type_name=None): if "acl" not in session: @@ -87,7 +82,9 @@ def can_access_resources(resource_type): else: g.resources = {resource_type: result} return func(*args, **kwargs) + return wrapper_can_access_resources + return decorator_can_access_resources @@ -102,7 +99,9 @@ def has_perm(resources, resource_type, perm): validate_permission(resources, resource_type, perm) return func(*args, **kwargs) + return wrapper_has_perm + return decorator_has_perm @@ -120,7 +119,9 @@ def has_perm_from_args(arg_name, resource_type, perm, callback=None): validate_permission(resource, resource_type, perm) return func(*args, **kwargs) + return wrapper_has_perm + return decorator_has_perm @@ -135,5 +136,7 @@ def role_required(role_name): if role_name not in session.get("acl", {}).get("parentRoles", []): return abort(403, "Role {0} is required".format(role_name)) return func(*args, **kwargs) + return wrapper_role_required + return decorator_role_required diff --git a/api/lib/perm/acl/resource.py b/api/lib/perm/acl/resource.py index dcc08f8..295ffbe 100644 --- a/api/lib/perm/acl/resource.py +++ b/api/lib/perm/acl/resource.py @@ -36,11 +36,11 @@ class ResourceTypeCRUD(object): return [i.to_dict() for i in perms] @classmethod - def add(cls, app_id, name, perms): + def add(cls, app_id, name, description, perms): ResourceType.get_by(name=name, app_id=app_id) and abort( 400, "ResourceType <{0}> is already existed".format(name)) - rt = ResourceType.create(name=name, app_id=app_id) + rt = ResourceType.create(name=name, description=description, app_id=app_id) cls.update_perms(rt.id, perms, app_id) diff --git a/api/lib/perm/acl/role.py b/api/lib/perm/acl/role.py index 5f12bab..ab128ab 100644 --- a/api/lib/perm/acl/role.py +++ b/api/lib/perm/acl/role.py @@ -23,8 +23,8 @@ class RoleRelationCRUD(object): if uids is not None: uids = [uids] if isinstance(uids, six.integer_types) else uids rids = db.session.query(Role).filter(Role.deleted.is_(False)).filter(Role.uid.in_(uids)) - rid2uid = {i.rid: i.uid for i in rids} - rids = [i.rid for i in rids] + rid2uid = {i.id: i.uid for i in rids} + rids = [i.id for i in rids] else: rids = [rids] if isinstance(rids, six.integer_types) else rids @@ -98,9 +98,12 @@ class RoleRelationCRUD(object): class RoleCRUD(object): @staticmethod - def search(q, app_id, page=1, page_size=None): - query = db.session.query(Role).filter(Role.deleted.is_(False)).filter( - Role.app_id == app_id).filter(Role.uid.is_(None)) + def search(q, app_id, page=1, page_size=None, user_role=False): + query = db.session.query(Role).filter(Role.deleted.is_(False)).filter(Role.app_id == app_id) + + if not user_role: + query = query.filter(Role.uid.is_(None)) + if q: query = query.filter(Role.name.ilike('%{0}%'.format(q))) @@ -109,7 +112,7 @@ class RoleCRUD(object): return numfound, query.offset((page - 1) * page_size).limit(page_size) @staticmethod - def add_role(name, app_id, is_app_admin=False, uid=None): + def add_role(name, app_id=None, is_app_admin=False, uid=None): Role.get_by(name=name, app_id=app_id) and abort(400, "Role <{0}> is already existed".format(name)) return Role.create(name=name, diff --git a/api/lib/perm/acl/user.py b/api/lib/perm/acl/user.py index 2a21fa1..7549236 100644 --- a/api/lib/perm/acl/user.py +++ b/api/lib/perm/acl/user.py @@ -1,15 +1,17 @@ # -*- coding:utf-8 -*- -import uuid -import string import random +import string +import uuid from flask import abort from flask import g from api.extensions import db from api.lib.perm.acl.cache import UserCache +from api.lib.perm.acl.role import RoleCRUD +from api.models.acl import Role from api.models.acl import User @@ -40,14 +42,28 @@ class UserCRUD(object): kwargs['block'] = 0 kwargs['key'], kwargs['secret'] = cls._gen_key_secret() - return User.create(**kwargs) + user = User.create(**kwargs) + + RoleCRUD.add_role(user.username, uid=user.uid) + + return user @staticmethod def update(uid, **kwargs): user = User.get_by(uid=uid, to_dict=False, first=True) or abort(404, "User <{0}> does not exist".format(uid)) + if kwargs.get("username"): + other = User.get_by(username=kwargs['username'], first=True, to_dict=False) + if other is not None and other.uid != user.uid: + return abort(400, "User <{0}> cannot be duplicated".format(kwargs['username'])) + UserCache.clean(user) + if kwargs.get("username") and kwargs['username'] != user.username: + role = Role.get_by(name=user.username, first=True, to_dict=False) + if role is not None: + RoleCRUD.update_role(role.id, **dict(name=kwargs['name'])) + return user.update(**kwargs) @classmethod diff --git a/api/views/acl/resources.py b/api/views/acl/resources.py index 37c593a..7712f95 100644 --- a/api/views/acl/resources.py +++ b/api/views/acl/resources.py @@ -39,9 +39,10 @@ class ResourceTypeView(APIView): def post(self): name = request.values.get('name') app_id = request.values.get('app_id') + description = request.values.get('description', '') perms = request.values.get('perms') - rt = ResourceTypeCRUD.add(app_id, name, perms) + rt = ResourceTypeCRUD.add(app_id, name, description, perms) return self.jsonify(rt.to_dict()) diff --git a/api/views/acl/role.py b/api/views/acl/role.py index 6015d37..b896778 100644 --- a/api/views/acl/role.py +++ b/api/views/acl/role.py @@ -21,8 +21,9 @@ class RoleView(APIView): page_size = get_page_size(request.values.get("page_size")) q = request.values.get('q') app_id = request.values.get('app_id') + user_role = request.values.get('user_role', False) - numfound, roles = RoleCRUD.search(q, app_id, page, page_size) + numfound, roles = RoleCRUD.search(q, app_id, page, page_size, user_role) id2parents = RoleRelationCRUD.get_parents([i.id for i in roles]) diff --git a/ui/src/config/router.config.js b/ui/src/config/router.config.js index e9d9997..386dbeb 100644 --- a/ui/src/config/router.config.js +++ b/ui/src/config/router.config.js @@ -105,28 +105,28 @@ const cmdbRouter = [ children: [ { path: '/acl/users', - name: 'acl_users', + name: 'cmdb_acl_users', hideChildrenInMenu: true, component: () => import('@/views/acl/users'), meta: { title: '用户管理', keepAlive: true } }, { path: '/acl/roles', - name: 'acl_roles', + name: 'cmdb_acl_roles', hideChildrenInMenu: true, component: () => import('@/views/acl/roles'), meta: { title: '角色管理', keepAlive: true } }, { path: '/acl/resources', - name: 'acl_resources', + name: 'cmdb_acl_resources', hideChildrenInMenu: true, component: () => import('@/views/acl/resources'), meta: { title: '资源管理', keepAlive: true } }, { path: '/acl/resource_types', - name: 'acl_resource_types', + name: 'cmdb_acl_resource_types', hideChildrenInMenu: true, component: () => import('@/views/acl/resource_types'), meta: { title: '资源类型', keepAlive: true } diff --git a/ui/src/views/acl/module/permissionForm.vue b/ui/src/views/acl/module/permissionForm.vue index c7be895..6776491 100644 --- a/ui/src/views/acl/module/permissionForm.vue +++ b/ui/src/views/acl/module/permissionForm.vue @@ -167,7 +167,7 @@ export default { if (!err) { console.log('Received values of form: ', values) - values.app_id = this.$store.state.app.name + values.app_id = this.$route.name.split('_')[0] values.perms = this.perms if (values.id) { this.updateResourceType(values.id, values) diff --git a/ui/src/views/acl/module/resourceForm.vue b/ui/src/views/acl/module/resourceForm.vue index 0b33211..a6b9a91 100644 --- a/ui/src/views/acl/module/resourceForm.vue +++ b/ui/src/views/acl/module/resourceForm.vue @@ -64,7 +64,7 @@ diff --git a/ui/src/views/acl/module/resourcePermManageForm.vue b/ui/src/views/acl/module/resourcePermManageForm.vue new file mode 100644 index 0000000..dc6c907 --- /dev/null +++ b/ui/src/views/acl/module/resourcePermManageForm.vue @@ -0,0 +1,120 @@ + + + diff --git a/ui/src/views/acl/module/resourceTypeForm.vue b/ui/src/views/acl/module/resourceTypeForm.vue index c630bb5..151bb1b 100644 --- a/ui/src/views/acl/module/resourceTypeForm.vue +++ b/ui/src/views/acl/module/resourceTypeForm.vue @@ -17,8 +17,8 @@ > @@ -123,6 +123,7 @@ export default { }, onClose () { this.form.resetFields() + this.perms = [] this.drawerVisible = false }, onChange (e) { @@ -148,7 +149,7 @@ export default { if (!err) { console.log('Received values of form: ', values) - values.app_id = this.$store.state.app.name + values.app_id = this.$route.name.split('_')[0] values.perms = this.perms if (values.id) { this.updateResourceType(values.id, values) diff --git a/ui/src/views/acl/module/roleForm.vue b/ui/src/views/acl/module/roleForm.vue index d56955b..ce01ff4 100644 --- a/ui/src/views/acl/module/roleForm.vue +++ b/ui/src/views/acl/module/roleForm.vue @@ -11,8 +11,8 @@ + + {{ role.name }} + + + - 确定 取消 - @@ -65,7 +74,7 @@