mirror of https://github.com/veops/cmdb.git
update acl
This commit is contained in:
parent
3b62bd7ac9
commit
0439e2462b
|
@ -23,7 +23,7 @@ from api.extensions import (
|
||||||
rd,
|
rd,
|
||||||
)
|
)
|
||||||
from api.flask_cas import CAS
|
from api.flask_cas import CAS
|
||||||
from api.models.account import User
|
from api.models.acl import User
|
||||||
|
|
||||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||||
PROJECT_ROOT = os.path.join(HERE, os.pardir)
|
PROJECT_ROOT = os.path.join(HERE, os.pardir)
|
||||||
|
|
|
@ -8,7 +8,7 @@ from flask import current_app, session, request, url_for, redirect
|
||||||
from flask_login import login_user, logout_user
|
from flask_login import login_user, logout_user
|
||||||
from six.moves.urllib_request import urlopen
|
from six.moves.urllib_request import urlopen
|
||||||
|
|
||||||
from api.models.account import UserCache
|
from api.lib.perm.acl.cache import UserCache
|
||||||
from .cas_urls import create_cas_login_url
|
from .cas_urls import create_cas_login_url
|
||||||
from .cas_urls import create_cas_logout_url
|
from .cas_urls import create_cas_logout_url
|
||||||
from .cas_urls import create_cas_validate_url
|
from .cas_urls import create_cas_validate_url
|
||||||
|
|
|
@ -7,7 +7,7 @@ from flask import g
|
||||||
from api.extensions import db
|
from api.extensions import db
|
||||||
from api.lib.cmdb.cache import AttributeCache
|
from api.lib.cmdb.cache import AttributeCache
|
||||||
from api.lib.cmdb.cache import RelationTypeCache
|
from api.lib.cmdb.cache import RelationTypeCache
|
||||||
from api.models.account import UserCache
|
from api.lib.perm.acl.cache import UserCache
|
||||||
from api.models.cmdb import Attribute
|
from api.models.cmdb import Attribute
|
||||||
from api.models.cmdb import AttributeHistory
|
from api.models.cmdb import AttributeHistory
|
||||||
from api.models.cmdb import CIRelationHistory
|
from api.models.cmdb import CIRelationHistory
|
||||||
|
|
|
@ -3,6 +3,39 @@
|
||||||
from api.extensions import cache
|
from api.extensions import cache
|
||||||
from api.models.acl import Permission
|
from api.models.acl import Permission
|
||||||
from api.models.acl import Role
|
from api.models.acl import Role
|
||||||
|
from api.models.acl import User
|
||||||
|
|
||||||
|
|
||||||
|
class UserCache(object):
|
||||||
|
PREFIX_ID = "User::uid::{0}"
|
||||||
|
PREFIX_NAME = "User::username::{0}"
|
||||||
|
PREFIX_NICK = "User::nickname::{0}"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get(cls, key):
|
||||||
|
user = cache.get(cls.PREFIX_ID.format(key)) or \
|
||||||
|
cache.get(cls.PREFIX_NAME.format(key)) or \
|
||||||
|
cache.get(cls.PREFIX_NICK.format(key))
|
||||||
|
if not user:
|
||||||
|
user = User.query.get(key) or \
|
||||||
|
User.query.get_by_username(key) or \
|
||||||
|
User.query.get_by_nickname(key)
|
||||||
|
if user:
|
||||||
|
cls.set(user)
|
||||||
|
|
||||||
|
return user
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set(cls, user):
|
||||||
|
cache.set(cls.PREFIX_ID.format(user.uid), user)
|
||||||
|
cache.set(cls.PREFIX_NAME.format(user.username), user)
|
||||||
|
cache.set(cls.PREFIX_NICK.format(user.nickname), user)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clean(cls, user):
|
||||||
|
cache.delete(cls.PREFIX_ID.format(user.uid))
|
||||||
|
cache.delete(cls.PREFIX_NAME.format(user.username))
|
||||||
|
cache.delete(cls.PREFIX_NICK.format(user.nickname))
|
||||||
|
|
||||||
|
|
||||||
class RoleCache(object):
|
class RoleCache(object):
|
||||||
|
|
|
@ -18,13 +18,21 @@ from api.tasks.acl import role_rebuild
|
||||||
|
|
||||||
class RoleRelationCRUD(object):
|
class RoleRelationCRUD(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_parents(rids):
|
def get_parents(rids=None, uids=None):
|
||||||
rids = [rids] if isinstance(rids, six.integer_types) else rids
|
rid2uid = dict()
|
||||||
|
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]
|
||||||
|
else:
|
||||||
|
rids = [rids] if isinstance(rids, six.integer_types) else rids
|
||||||
|
|
||||||
res = db.session.query(RoleRelation).filter(
|
res = db.session.query(RoleRelation).filter(
|
||||||
RoleRelation.child_id.in_(rids)).filter(RoleRelation.deleted.is_(False))
|
RoleRelation.child_id.in_(rids)).filter(RoleRelation.deleted.is_(False))
|
||||||
id2parents = {}
|
id2parents = {}
|
||||||
for i in res:
|
for i in res:
|
||||||
id2parents.setdefault(i.child_id, []).append(RoleCache.get(i.parent_id).to_dict())
|
id2parents.setdefault(rid2uid.get(i.child_id, i.child_id), []).append(RoleCache.get(i.parent_id).to_dict())
|
||||||
|
|
||||||
return id2parents
|
return id2parents
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
from flask import abort
|
||||||
|
|
||||||
|
from api.extensions import db
|
||||||
|
from api.lib.perm.acl.cache import UserCache
|
||||||
|
from api.models.acl import User
|
||||||
|
|
||||||
|
|
||||||
|
class UserCRUD(object):
|
||||||
|
@staticmethod
|
||||||
|
def search(q, page=1, page_size=None):
|
||||||
|
query = db.session.query(User).filter(User.deleted.is_(False))
|
||||||
|
if q:
|
||||||
|
query = query.filter(User.username.ilike('%{0}%'.format(q)))
|
||||||
|
|
||||||
|
numfound = query.count()
|
||||||
|
|
||||||
|
return numfound, query.offset((page - 1) * page_size).limit(page_size)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def add(**kwargs):
|
||||||
|
existed = User.get_by(username=kwargs['username'], email=kwargs['email'])
|
||||||
|
existed and abort(400, "User <{0}> is already existed".format(kwargs['username']))
|
||||||
|
|
||||||
|
kwargs['nickname'] = kwargs['username'] if not kwargs.get('nickname') else kwargs['nickname']
|
||||||
|
kwargs['block'] = 0
|
||||||
|
return User.create(**kwargs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def update(rid, **kwargs):
|
||||||
|
user = User.get_by_id(rid) or abort(404, "User <{0}> does not exist".format(rid))
|
||||||
|
|
||||||
|
UserCache.clean(rid)
|
||||||
|
|
||||||
|
return user.update(**kwargs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def delete(cls, uid):
|
||||||
|
user = User.get_by_id(uid) or abort(404, "User <{0}> does not exist".format(uid))
|
||||||
|
|
||||||
|
UserCache.clean(user)
|
||||||
|
|
||||||
|
user.soft_delete()
|
|
@ -13,8 +13,8 @@ from flask import request
|
||||||
from flask import session
|
from flask import session
|
||||||
from flask_login import login_user
|
from flask_login import login_user
|
||||||
|
|
||||||
from api.models.account import User
|
from api.models.acl import User
|
||||||
from api.models.account import UserCache
|
from api.lib.perm.acl.cache import UserCache
|
||||||
|
|
||||||
|
|
||||||
def _auth_with_key():
|
def _auth_with_key():
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
from .account import User
|
|
||||||
from .cmdb import *
|
from .cmdb import *
|
||||||
from .acl import *
|
from .acl import *
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
# -*- coding:utf-8 -*-
|
|
||||||
|
|
||||||
import copy
|
|
||||||
import hashlib
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from flask import current_app
|
|
||||||
from flask_sqlalchemy import BaseQuery
|
|
||||||
|
|
||||||
from api.extensions import cache
|
|
||||||
from api.extensions import db
|
|
||||||
from api.lib.database import CRUDModel
|
|
||||||
|
|
||||||
|
|
||||||
class UserQuery(BaseQuery):
|
|
||||||
def _join(self, *args, **kwargs):
|
|
||||||
super(UserQuery, self)._join(*args, **kwargs)
|
|
||||||
|
|
||||||
def authenticate(self, login, password):
|
|
||||||
user = self.filter(db.or_(User.username == login,
|
|
||||||
User.email == login)).first()
|
|
||||||
if user:
|
|
||||||
current_app.logger.info(user)
|
|
||||||
authenticated = user.check_password(password)
|
|
||||||
else:
|
|
||||||
authenticated = False
|
|
||||||
return user, authenticated
|
|
||||||
|
|
||||||
def authenticate_with_key(self, key, secret, args, path):
|
|
||||||
user = self.filter(User.key == key).filter(User.block == 0).first()
|
|
||||||
if not user:
|
|
||||||
return None, False
|
|
||||||
if user and hashlib.sha1('{0}{1}{2}'.format(
|
|
||||||
path, user.secret, "".join(args)).encode("utf-8")).hexdigest() == secret:
|
|
||||||
authenticated = True
|
|
||||||
else:
|
|
||||||
authenticated = False
|
|
||||||
return user, authenticated
|
|
||||||
|
|
||||||
def search(self, key):
|
|
||||||
query = self.filter(db.or_(User.email == key,
|
|
||||||
User.nickname.ilike('%' + key + '%'),
|
|
||||||
User.username.ilike('%' + key + '%')))
|
|
||||||
return query
|
|
||||||
|
|
||||||
def get_by_username(self, username):
|
|
||||||
user = self.filter(User.username == username).first()
|
|
||||||
return user
|
|
||||||
|
|
||||||
def get_by_nickname(self, nickname):
|
|
||||||
user = self.filter(User.nickname == nickname).first()
|
|
||||||
return user
|
|
||||||
|
|
||||||
def get(self, uid):
|
|
||||||
user = self.filter(User.uid == uid).first()
|
|
||||||
return copy.deepcopy(user)
|
|
||||||
|
|
||||||
|
|
||||||
class User(CRUDModel):
|
|
||||||
__tablename__ = 'users'
|
|
||||||
__bind_key__ = "user"
|
|
||||||
query_class = UserQuery
|
|
||||||
|
|
||||||
uid = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
|
||||||
username = db.Column(db.String(32), unique=True)
|
|
||||||
nickname = db.Column(db.String(20), nullable=True)
|
|
||||||
department = db.Column(db.String(20))
|
|
||||||
catalog = db.Column(db.String(64))
|
|
||||||
email = db.Column(db.String(100), unique=True, nullable=False)
|
|
||||||
mobile = db.Column(db.String(14), unique=True)
|
|
||||||
_password = db.Column("password", db.String(80))
|
|
||||||
key = db.Column(db.String(32), nullable=False)
|
|
||||||
secret = db.Column(db.String(32), nullable=False)
|
|
||||||
date_joined = db.Column(db.DateTime, default=datetime.utcnow)
|
|
||||||
last_login = db.Column(db.DateTime, default=datetime.utcnow)
|
|
||||||
block = db.Column(db.Boolean, default=False)
|
|
||||||
has_logined = db.Column(db.Boolean, default=False)
|
|
||||||
wx_id = db.Column(db.String(32))
|
|
||||||
avatar = db.Column(db.String(128))
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.username
|
|
||||||
|
|
||||||
def is_active(self):
|
|
||||||
return not self.block
|
|
||||||
|
|
||||||
def get_id(self):
|
|
||||||
return self.uid
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def is_authenticated():
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _get_password(self):
|
|
||||||
return self._password
|
|
||||||
|
|
||||||
def _set_password(self, password):
|
|
||||||
self._password = hashlib.md5(password.encode('utf-8')).hexdigest()
|
|
||||||
|
|
||||||
password = db.synonym("_password",
|
|
||||||
descriptor=property(_get_password,
|
|
||||||
_set_password))
|
|
||||||
|
|
||||||
def check_password(self, password):
|
|
||||||
if self.password is None:
|
|
||||||
return False
|
|
||||||
return self.password == password
|
|
||||||
|
|
||||||
|
|
||||||
class UserCache(object):
|
|
||||||
PREFIX_ID = "User::uid::{0}"
|
|
||||||
PREFIX_NAME = "User::username::{0}"
|
|
||||||
PREFIX_NICK = "User::nickname::{0}"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get(cls, key):
|
|
||||||
user = cache.get(cls.PREFIX_ID.format(key)) or \
|
|
||||||
cache.get(cls.PREFIX_NAME.format(key)) or \
|
|
||||||
cache.get(cls.PREFIX_NICK.format(key))
|
|
||||||
if not user:
|
|
||||||
user = User.query.get(key) or \
|
|
||||||
User.query.get_by_username(key) or \
|
|
||||||
User.query.get_by_nickname(key)
|
|
||||||
if user:
|
|
||||||
cls.set(user)
|
|
||||||
|
|
||||||
return user
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def set(cls, user):
|
|
||||||
cache.set(cls.PREFIX_ID.format(user.uid), user)
|
|
||||||
cache.set(cls.PREFIX_NAME.format(user.username), user)
|
|
||||||
cache.set(cls.PREFIX_NICK.format(user.nickname), user)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def clean(cls, user):
|
|
||||||
cache.delete(cls.PREFIX_ID.format(user.uid))
|
|
||||||
cache.delete(cls.PREFIX_NAME.format(user.username))
|
|
||||||
cache.delete(cls.PREFIX_NICK.format(user.nickname))
|
|
|
@ -1,6 +1,15 @@
|
||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import hashlib
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from flask import current_app
|
||||||
|
from flask_sqlalchemy import BaseQuery
|
||||||
|
|
||||||
from api.extensions import db
|
from api.extensions import db
|
||||||
|
from api.lib.database import CRUDModel
|
||||||
from api.lib.database import Model
|
from api.lib.database import Model
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,6 +22,101 @@ class App(Model):
|
||||||
secret_key = db.Column(db.Text)
|
secret_key = db.Column(db.Text)
|
||||||
|
|
||||||
|
|
||||||
|
class UserQuery(BaseQuery):
|
||||||
|
def _join(self, *args, **kwargs):
|
||||||
|
super(UserQuery, self)._join(*args, **kwargs)
|
||||||
|
|
||||||
|
def authenticate(self, login, password):
|
||||||
|
user = self.filter(db.or_(User.username == login,
|
||||||
|
User.email == login)).first()
|
||||||
|
if user:
|
||||||
|
current_app.logger.info(user)
|
||||||
|
authenticated = user.check_password(password)
|
||||||
|
else:
|
||||||
|
authenticated = False
|
||||||
|
return user, authenticated
|
||||||
|
|
||||||
|
def authenticate_with_key(self, key, secret, args, path):
|
||||||
|
user = self.filter(User.key == key).filter(User.block == 0).first()
|
||||||
|
if not user:
|
||||||
|
return None, False
|
||||||
|
if user and hashlib.sha1('{0}{1}{2}'.format(
|
||||||
|
path, user.secret, "".join(args)).encode("utf-8")).hexdigest() == secret:
|
||||||
|
authenticated = True
|
||||||
|
else:
|
||||||
|
authenticated = False
|
||||||
|
return user, authenticated
|
||||||
|
|
||||||
|
def search(self, key):
|
||||||
|
query = self.filter(db.or_(User.email == key,
|
||||||
|
User.nickname.ilike('%' + key + '%'),
|
||||||
|
User.username.ilike('%' + key + '%')))
|
||||||
|
return query
|
||||||
|
|
||||||
|
def get_by_username(self, username):
|
||||||
|
user = self.filter(User.username == username).first()
|
||||||
|
return user
|
||||||
|
|
||||||
|
def get_by_nickname(self, nickname):
|
||||||
|
user = self.filter(User.nickname == nickname).first()
|
||||||
|
return user
|
||||||
|
|
||||||
|
def get(self, uid):
|
||||||
|
user = self.filter(User.uid == uid).first()
|
||||||
|
return copy.deepcopy(user)
|
||||||
|
|
||||||
|
|
||||||
|
class User(CRUDModel):
|
||||||
|
__tablename__ = 'users'
|
||||||
|
__bind_key__ = "user"
|
||||||
|
query_class = UserQuery
|
||||||
|
|
||||||
|
uid = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
||||||
|
username = db.Column(db.String(32), unique=True)
|
||||||
|
nickname = db.Column(db.String(20), nullable=True)
|
||||||
|
department = db.Column(db.String(20))
|
||||||
|
catalog = db.Column(db.String(64))
|
||||||
|
email = db.Column(db.String(100), unique=True, nullable=False)
|
||||||
|
mobile = db.Column(db.String(14), unique=True)
|
||||||
|
_password = db.Column("password", db.String(80))
|
||||||
|
key = db.Column(db.String(32), nullable=False)
|
||||||
|
secret = db.Column(db.String(32), nullable=False)
|
||||||
|
date_joined = db.Column(db.DateTime, default=datetime.utcnow)
|
||||||
|
last_login = db.Column(db.DateTime, default=datetime.utcnow)
|
||||||
|
block = db.Column(db.Boolean, default=False)
|
||||||
|
has_logined = db.Column(db.Boolean, default=False)
|
||||||
|
wx_id = db.Column(db.String(32))
|
||||||
|
avatar = db.Column(db.String(128))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.username
|
||||||
|
|
||||||
|
def is_active(self):
|
||||||
|
return not self.block
|
||||||
|
|
||||||
|
def get_id(self):
|
||||||
|
return self.uid
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_authenticated():
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _get_password(self):
|
||||||
|
return self._password
|
||||||
|
|
||||||
|
def _set_password(self, password):
|
||||||
|
self._password = hashlib.md5(password.encode('utf-8')).hexdigest()
|
||||||
|
|
||||||
|
password = db.synonym("_password",
|
||||||
|
descriptor=property(_get_password,
|
||||||
|
_set_password))
|
||||||
|
|
||||||
|
def check_password(self, password):
|
||||||
|
if self.password is None:
|
||||||
|
return False
|
||||||
|
return self.password == password
|
||||||
|
|
||||||
|
|
||||||
class Role(Model):
|
class Role(Model):
|
||||||
__tablename__ = "acl_roles"
|
__tablename__ = "acl_roles"
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ from flask import Blueprint
|
||||||
from flask_restful import Api
|
from flask_restful import Api
|
||||||
|
|
||||||
from api.resource import register_resources
|
from api.resource import register_resources
|
||||||
from .permission import GetResourcesView, HasPermissionView, GetUserInfoView
|
|
||||||
from .account import LoginView, LogoutView
|
from .account import LoginView, LogoutView
|
||||||
|
|
||||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
@ -17,13 +16,6 @@ account_rest = Api(blueprint_account)
|
||||||
account_rest.add_resource(LoginView, LoginView.url_prefix)
|
account_rest.add_resource(LoginView, LoginView.url_prefix)
|
||||||
account_rest.add_resource(LogoutView, LogoutView.url_prefix)
|
account_rest.add_resource(LogoutView, LogoutView.url_prefix)
|
||||||
|
|
||||||
# permission
|
|
||||||
blueprint_perm_v01 = Blueprint('permission_api', __name__, url_prefix='/api/v1/perms')
|
|
||||||
perm_rest = Api(blueprint_perm_v01)
|
|
||||||
perm_rest.add_resource(GetResourcesView, GetResourcesView.url_prefix)
|
|
||||||
perm_rest.add_resource(HasPermissionView, HasPermissionView.url_prefix)
|
|
||||||
perm_rest.add_resource(GetUserInfoView, GetUserInfoView.url_prefix)
|
|
||||||
|
|
||||||
|
|
||||||
# cmdb
|
# cmdb
|
||||||
blueprint_cmdb_v01 = Blueprint('cmdb_api_v01', __name__, url_prefix='/api/v0.1')
|
blueprint_cmdb_v01 = Blueprint('cmdb_api_v01', __name__, url_prefix='/api/v0.1')
|
||||||
|
|
|
@ -10,7 +10,7 @@ from flask_login import login_user, logout_user
|
||||||
|
|
||||||
from api.lib.decorator import args_required
|
from api.lib.decorator import args_required
|
||||||
from api.lib.perm.auth import auth_abandoned
|
from api.lib.perm.auth import auth_abandoned
|
||||||
from api.models.account import User
|
from api.models.acl import User
|
||||||
from api.resource import APIView
|
from api.resource import APIView
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@ class LoginView(APIView):
|
||||||
username = request.values.get("username") or request.values.get("email")
|
username = request.values.get("username") or request.values.get("email")
|
||||||
password = request.values.get("password")
|
password = request.values.get("password")
|
||||||
user, authenticated = User.query.authenticate(username, password)
|
user, authenticated = User.query.authenticate(username, password)
|
||||||
|
if not user:
|
||||||
|
return abort(403, "User <{0}> does not exist".format(username))
|
||||||
if not authenticated:
|
if not authenticated:
|
||||||
return abort(403, "invalid username or password")
|
return abort(403, "invalid username or password")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
from flask import request
|
||||||
|
from flask import session
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
|
from api.lib.decorator import args_required
|
||||||
|
from api.lib.perm.acl.user import UserCRUD
|
||||||
|
from api.lib.perm.acl.role import RoleRelationCRUD
|
||||||
|
from api.lib.utils import get_page
|
||||||
|
from api.lib.utils import get_page_size
|
||||||
|
from api.resource import APIView
|
||||||
|
|
||||||
|
|
||||||
|
class GetUserInfoView(APIView):
|
||||||
|
url_prefix = "/users/info"
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
name = session.get("acl", {}).get("nickName") or session.get("CAS_USERNAME") or current_user.nickname
|
||||||
|
role = dict(permissions=session.get("acl", {}).get("parentRoles", []) or ["admin"])
|
||||||
|
avatar = session.get("acl", {}).get("avatar") or current_user.avatar
|
||||||
|
return self.jsonify(result=dict(name=name,
|
||||||
|
role=role,
|
||||||
|
avatar=avatar))
|
||||||
|
|
||||||
|
|
||||||
|
class UserView(APIView):
|
||||||
|
url_prefix = ("/users", "/users/<int:uid>")
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
page = get_page(request.values.get('page', 1))
|
||||||
|
page_size = get_page_size(request.values.get('page_size'))
|
||||||
|
q = request.values.get("q")
|
||||||
|
numfound, users = UserCRUD.search(q, page, page_size)
|
||||||
|
|
||||||
|
id2parents = RoleRelationCRUD.get_parents(uids=[i.uid for i in users])
|
||||||
|
|
||||||
|
return self.jsonify(numfound=numfound,
|
||||||
|
page=page,
|
||||||
|
page_size=page_size,
|
||||||
|
id2parents=id2parents,
|
||||||
|
users=[i.to_dict() for i in users])
|
||||||
|
|
||||||
|
@args_required('username')
|
||||||
|
@args_required('email')
|
||||||
|
def post(self):
|
||||||
|
user = UserCRUD.add(**request.values)
|
||||||
|
|
||||||
|
return self.jsonify(user.to_dict())
|
||||||
|
|
||||||
|
def put(self, uid):
|
||||||
|
user = UserCRUD.update(uid, **request.values)
|
||||||
|
|
||||||
|
return self.jsonify(user.to_dict())
|
||||||
|
|
||||||
|
def delete(self, uid):
|
||||||
|
UserCRUD.delete(uid)
|
||||||
|
|
||||||
|
return self.jsonify(uid=uid)
|
|
@ -1,49 +0,0 @@
|
||||||
# -*- coding:utf-8 -*-
|
|
||||||
|
|
||||||
from flask import request
|
|
||||||
from flask import session
|
|
||||||
from flask_login import current_user
|
|
||||||
|
|
||||||
from api.lib.decorator import args_required
|
|
||||||
from api.lib.perm.acl.acl import ACLManager
|
|
||||||
from api.lib.perm.acl.acl import validate_permission
|
|
||||||
from api.resource import APIView
|
|
||||||
|
|
||||||
|
|
||||||
class HasPermissionView(APIView):
|
|
||||||
url_prefix = "/validate"
|
|
||||||
|
|
||||||
@args_required("resource")
|
|
||||||
@args_required("resource_type")
|
|
||||||
@args_required("perm")
|
|
||||||
def get(self):
|
|
||||||
resource = request.values.get("resource")
|
|
||||||
resource_type = request.values.get("resource_type")
|
|
||||||
perm = request.values.get("perm")
|
|
||||||
validate_permission(resource, resource_type, perm)
|
|
||||||
return self.jsonify(is_valid=True)
|
|
||||||
|
|
||||||
def post(self):
|
|
||||||
self.get()
|
|
||||||
|
|
||||||
|
|
||||||
class GetResourcesView(APIView):
|
|
||||||
url_prefix = "/resources"
|
|
||||||
|
|
||||||
@args_required("resource_type")
|
|
||||||
def get(self):
|
|
||||||
resource_type = request.values.get("resource_type")
|
|
||||||
res = ACLManager().get_resources(resource_type)
|
|
||||||
return self.jsonify(res)
|
|
||||||
|
|
||||||
|
|
||||||
class GetUserInfoView(APIView):
|
|
||||||
url_prefix = "/user/info"
|
|
||||||
|
|
||||||
def get(self):
|
|
||||||
name = session.get("acl", {}).get("nickName") or session.get("CAS_USERNAME") or current_user.nickname
|
|
||||||
role = dict(permissions=session.get("acl", {}).get("parentRoles", []) or ["admin"])
|
|
||||||
avatar = session.get("acl", {}).get("avatar") or current_user.avatar
|
|
||||||
return self.jsonify(result=dict(name=name,
|
|
||||||
role=role,
|
|
||||||
avatar=avatar))
|
|
|
@ -9,6 +9,6 @@ const api = {
|
||||||
SendSms: '/account/sms',
|
SendSms: '/account/sms',
|
||||||
SendSmsErr: '/account/sms_err',
|
SendSmsErr: '/account/sms_err',
|
||||||
// get my info
|
// get my info
|
||||||
UserInfo: '/v1/perms/user/info'
|
UserInfo: '/v1/acl/users/info'
|
||||||
}
|
}
|
||||||
export default api
|
export default api
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="user-wrapper">
|
<div class="user-wrapper">
|
||||||
<div class="content-box">
|
<div class="content-box">
|
||||||
|
<a href="https://github.com/pycook/cmdb" target="_blank">
|
||||||
|
<span class="action">
|
||||||
|
源代码 -> <a-icon type="github" style="font-size: 20px; color: #002140"></a-icon>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
<!-- <a href="https://pro.loacg.com/docs/getting-started" target="_blank">
|
<!-- <a href="https://pro.loacg.com/docs/getting-started" target="_blank">
|
||||||
<span class="action">
|
<span class="action">
|
||||||
<a-icon type="question-circle-o"></a-icon>
|
<a-icon type="question-circle-o"></a-icon>
|
||||||
</span>
|
</span>
|
||||||
</a> -->
|
</a>
|
||||||
<!-- <notice-icon class="action"/> -->
|
<notice-icon class="action"/> -->
|
||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
<span class="action ant-dropdown-link user-dropdown-menu">
|
<span class="action ant-dropdown-link user-dropdown-menu">
|
||||||
<a-avatar class="avatar" size="small" :src="avatar()"/>
|
<a-avatar class="avatar" size="small" :src="avatar()"/>
|
||||||
|
@ -25,10 +30,6 @@
|
||||||
<span>账户设置</span>
|
<span>账户设置</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="2" disabled>
|
|
||||||
<a-icon type="setting"/>
|
|
||||||
<span>测试</span>
|
|
||||||
</a-menu-item>
|
|
||||||
<a-menu-divider/> -->
|
<a-menu-divider/> -->
|
||||||
<a-menu-item key="3">
|
<a-menu-item key="3">
|
||||||
<a href="javascript:;" @click="handleLogout">
|
<a href="javascript:;" @click="handleLogout">
|
||||||
|
|
|
@ -65,6 +65,36 @@ const cmdbRouter = [
|
||||||
meta: { title: '属性库', keepAlive: true }
|
meta: { title: '属性库', keepAlive: true }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/acl',
|
||||||
|
name: 'cmdb_acl',
|
||||||
|
component: RouteView,
|
||||||
|
redirect: '/acl/users',
|
||||||
|
meta: { title: '权限管理', icon: 'safety-certificate', permission: ['admin'] },
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/acl/users',
|
||||||
|
name: 'acl_users',
|
||||||
|
hideChildrenInMenu: true,
|
||||||
|
component: () => import('@/views/cmdb/acl/users'),
|
||||||
|
meta: { title: 'Users', keepAlive: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/acl/roles',
|
||||||
|
name: 'acl_roles',
|
||||||
|
hideChildrenInMenu: true,
|
||||||
|
component: () => import('@/views/cmdb/acl/roles'),
|
||||||
|
meta: { title: 'Roles', keepAlive: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/acl/resources',
|
||||||
|
name: 'acl_resources',
|
||||||
|
hideChildrenInMenu: true,
|
||||||
|
component: () => import('@/views/cmdb/acl/resources'),
|
||||||
|
meta: { title: 'Resources', keepAlive: true }
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import notification from 'ant-design-vue/es/notification'
|
|
||||||
import { VueAxios } from './axios'
|
import { VueAxios } from './axios'
|
||||||
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||||
|
|
||||||
|
@ -15,13 +14,6 @@ const service = axios.create({
|
||||||
|
|
||||||
const err = (error) => {
|
const err = (error) => {
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
const data = error.response.data
|
|
||||||
if (error.response.status === 403) {
|
|
||||||
notification.error({
|
|
||||||
message: 'Forbidden',
|
|
||||||
description: data.message
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if (error.response.status === 401) {
|
if (error.response.status === 401) {
|
||||||
store.dispatch('Logout')
|
store.dispatch('Logout')
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
Loading…
Reference in New Issue