Skip to content

Commit 04642eb

Browse files
committed
feat: authentication
1 parent 5ffd342 commit 04642eb

File tree

11 files changed

+348
-35
lines changed

11 files changed

+348
-35
lines changed

Diff for: apps/common/auth/authenticate.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
from django.conf import settings
1313
from django.core import cache
1414
from django.core import signing
15+
from django.utils.translation import gettext_lazy as _
1516
from rest_framework.authentication import TokenAuthentication
1617

1718
from common.exception.app_exception import AppAuthenticationFailed, AppEmbedIdentityFailed, AppChatNumOutOfBoundsFailed, \
18-
ChatException, AppApiException
19-
from django.utils.translation import gettext_lazy as _
19+
AppApiException
2020

2121
token_cache = cache.caches['default']
2222

Diff for: apps/common/auth/authentication.py

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# coding=utf-8
2+
"""
3+
@project: MaxKB
4+
@Author:虎虎
5+
@file: authentication.py
6+
@date:2025/4/15 20:12
7+
@desc:
8+
"""
9+
from typing import List
10+
11+
from django.utils.translation import gettext_lazy as _
12+
13+
from common.constants.permission_constants import PermissionConstants, RoleConstants, ViewPermission, CompareConstants, \
14+
Permission
15+
from common.exception.app_exception import AppUnauthorizedFailed
16+
17+
18+
def exist_permissions_by_permission_constants(user_permission: List[PermissionConstants],
19+
permission_list: List[PermissionConstants]):
20+
"""
21+
用户是否拥有 permission_list的权限
22+
:param user_permission: 用户权限
23+
:param permission_list: 需要的权限
24+
:return: 是否拥有
25+
"""
26+
return any(list(map(lambda up: permission_list.__contains__(up), user_permission)))
27+
28+
29+
def exist_role_by_role_constants(user_role: List[RoleConstants],
30+
role_list: List[RoleConstants]):
31+
"""
32+
用户是否拥有这个角色
33+
:param user_role: 用户角色
34+
:param role_list: 需要拥有的角色
35+
:return: 是否拥有
36+
"""
37+
return any(list(map(lambda up: role_list.__contains__(up), user_role)))
38+
39+
40+
def exist_permissions_by_view_permission(user_role: List[RoleConstants],
41+
user_permission: List[PermissionConstants | object],
42+
permission: ViewPermission, request, **kwargs):
43+
"""
44+
用户是否存在这些权限
45+
:param request:
46+
:param user_role: 用户角色
47+
:param user_permission: 用户权限
48+
:param permission: 所属权限
49+
:return: 是否存在 True False
50+
"""
51+
role_ok = any(list(map(lambda ur: permission.roleList.__contains__(ur), user_role)))
52+
permission_list = [user_p(request, kwargs) if callable(user_p) else user_p for user_p in
53+
permission.permissionList
54+
]
55+
permission_ok = any(list(map(lambda up: permission_list.__contains__(up),
56+
user_permission)))
57+
return role_ok | permission_ok if permission.compare == CompareConstants.OR else role_ok & permission_ok
58+
59+
60+
def exist_permissions(user_role: List[RoleConstants], user_permission: List[PermissionConstants], permission, request,
61+
**kwargs):
62+
if isinstance(permission, ViewPermission):
63+
return exist_permissions_by_view_permission(user_role, user_permission, permission, request, **kwargs)
64+
if isinstance(permission, RoleConstants):
65+
return exist_role_by_role_constants(user_role, [permission])
66+
if isinstance(permission, PermissionConstants):
67+
return exist_permissions_by_permission_constants(user_permission, [permission])
68+
if isinstance(permission, Permission):
69+
return user_permission.__contains__(permission)
70+
return False
71+
72+
73+
def exist(user_role: List[RoleConstants], user_permission: List[PermissionConstants], permission, request, **kwargs):
74+
if callable(permission):
75+
p = permission(request, kwargs)
76+
return exist_permissions(user_role, user_permission, p, request)
77+
return exist_permissions(user_role, user_permission, permission, request, **kwargs)
78+
79+
80+
def has_permissions(*permission, compare=CompareConstants.OR):
81+
"""
82+
权限 role or permission
83+
:param compare: 比较符号
84+
:param permission: 如果是角色 role:roleId
85+
:return: 权限装饰器函数,用于判断用户是否有权限访问当前接口
86+
"""
87+
88+
def inner(func):
89+
def run(view, request, **kwargs):
90+
exit_list = list(
91+
map(lambda p: exist(request.auth.current_role_list, request.auth.permission_list, p, request, **kwargs),
92+
permission))
93+
# 判断是否有权限
94+
if any(exit_list) if compare == CompareConstants.OR else all(exit_list):
95+
return func(view, request, **kwargs)
96+
raise AppUnauthorizedFailed(403, _('No permission to access'))
97+
98+
return run
99+
100+
return inner

Diff for: apps/common/auth/handle/impl/user_token.py

+98-10
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,107 @@
11
# coding=utf-8
22
"""
3-
@project: maxkb
3+
@project: MaxKB
44
@Author:虎虎
55
@file: authenticate.py
66
@date:2024/3/14 03:02
77
@desc: 用户认证
88
"""
9+
from django.core.cache import cache
910
from django.db.models import QuerySet
11+
from django.utils.translation import gettext_lazy as _
12+
1013
from common.auth.handle.auth_base_handle import AuthBaseHandle
11-
from common.constants.authentication_type import AuthenticationType
1214
from common.constants.cache_version import Cache_Version
13-
from common.constants.permission_constants import Auth, RoleConstants
15+
from common.constants.permission_constants import Auth, RoleConstants, get_default_permission_list_by_role
16+
from common.database_model_manage.database_model_manage import DatabaseModelManage
1417
from common.exception.app_exception import AppAuthenticationFailed
1518
from users.models import User
16-
from django.core.cache import cache
17-
from django.utils.translation import gettext_lazy as _
19+
20+
21+
def get_permission_list(user_id,
22+
workspace_id,
23+
workspace_user_role_mapping_model,
24+
workspace_model,
25+
role_model,
26+
role_permission_mapping_model):
27+
version, get_key = Cache_Version.PERMISSION_LIST.value
28+
key = get_key(user_id, workspace_id)
29+
# 获取权限列表
30+
is_query_model = workspace_user_role_mapping_model is not None and workspace_model is not None and role_model is not None and role_permission_mapping_model is not None
31+
permission_list = cache.get(key, version=version)
32+
if permission_list is None:
33+
if is_query_model:
34+
# 获取工作空间 用户 角色映射数据
35+
workspace_user_role_mapping_list = QuerySet(workspace_user_role_mapping_model).filter(user_id=user_id)
36+
# 获取角色权限映射数据
37+
role_permission_mapping_list = QuerySet(role_permission_mapping_model).filter(
38+
role_id__in=[workspace_user_role_mapping.role_id for workspace_user_role_mapping in
39+
workspace_user_role_mapping_list])
40+
permission_list = [role_model.id for role_model in role_permission_mapping_list]
41+
cache.set(key, permission_list, version=version)
42+
else:
43+
permission_list = get_default_permission_list_by_role(RoleConstants.ADMIN)
44+
cache.set(key, permission_list, version=version)
45+
return permission_list
46+
47+
48+
def get_workspace_list(user_id,
49+
workspace_id,
50+
workspace_user_role_mapping_model,
51+
workspace_model,
52+
role_model,
53+
role_permission_mapping_model):
54+
version, get_key = Cache_Version.WORKSPACE_LIST.value
55+
key = get_key(user_id)
56+
workspace_list = cache.get(key, version=version)
57+
# 获取权限列表
58+
is_query_model = workspace_user_role_mapping_model is not None and workspace_model is not None and role_model is not None and role_permission_mapping_model is not None
59+
if workspace_list is None:
60+
if is_query_model:
61+
# 获取工作空间 用户 角色映射数据
62+
workspace_user_role_mapping_list = QuerySet(workspace_user_role_mapping_model).filter(user_id=user_id)
63+
cache.set(key, [workspace_user_role_mapping.workspace_id for workspace_user_role_mapping in
64+
workspace_user_role_mapping_list], version=version)
65+
else:
66+
return ["default"]
67+
return workspace_list
68+
69+
70+
def get_role_list(user,
71+
workspace_id,
72+
workspace_user_role_mapping_model,
73+
workspace_model,
74+
role_model,
75+
role_permission_mapping_model):
76+
version, get_key = Cache_Version.ROLE_LIST.value
77+
key = get_key(user.id, workspace_id)
78+
workspace_list = cache.get(key, version=version)
79+
# 获取权限列表
80+
is_query_model = workspace_user_role_mapping_model is not None and workspace_model is not None and role_model is not None and role_permission_mapping_model is not None
81+
if workspace_list is None:
82+
if is_query_model:
83+
# 获取工作空间 用户 角色映射数据
84+
workspace_user_role_mapping_list = QuerySet(workspace_user_role_mapping_model).filter(user_id=user.id)
85+
cache.set(key, [workspace_user_role_mapping.role_id for workspace_user_role_mapping in
86+
workspace_user_role_mapping_list], version=version)
87+
else:
88+
cache.set(key, [user.role], version=version)
89+
return [user.role]
90+
return workspace_list
91+
92+
93+
def get_auth(user, workspace_id):
94+
workspace_user_role_mapping_model = DatabaseModelManage.get_model("workspace_user_role_mapping")
95+
workspace_model = DatabaseModelManage.get_model("workspace_model")
96+
role_model = DatabaseModelManage.get_model("role_model")
97+
role_permission_mapping_model = DatabaseModelManage.get_model("role_permission_mapping_model")
98+
workspace_list = get_workspace_list(user.id, workspace_id, workspace_user_role_mapping_model, workspace_model,
99+
role_model, role_permission_mapping_model)
100+
permission_list = get_permission_list(user.id, workspace_id, workspace_user_role_mapping_model, workspace_model,
101+
role_model, role_permission_mapping_model)
102+
role_list = get_role_list(user, workspace_id, workspace_user_role_mapping_model, workspace_model,
103+
role_model, role_permission_mapping_model)
104+
return Auth(workspace_list, workspace_id, role_list, permission_list)
18105

19106

20107
class UserToken(AuthBaseHandle):
@@ -25,12 +112,13 @@ def support(self, request, token: str, get_token_details):
25112
return True
26113

27114
def handle(self, request, token: str, get_token_details):
28-
cache_token = cache.get(token, version=Cache_Version.TOKEN)
115+
version, get_key = Cache_Version.TOKEN.value
116+
cache_token = cache.get(get_key(token), version=version)
29117
if cache_token is None:
30118
raise AppAuthenticationFailed(1002, _('Login expired'))
31119
auth_details = get_token_details()
120+
# 当前工作空间
121+
current_workspace = auth_details['current_workspace']
32122
user = QuerySet(User).get(id=auth_details['id'])
33-
role = RoleConstants[user.role]
34-
return user, Auth([], [],
35-
client_id=str(user.id),
36-
client_type=AuthenticationType.SYSTEM_USER.value, current_role=role)
123+
auth = get_auth(user, current_workspace)
124+
return user, auth

Diff for: apps/common/constants/cache_version.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,16 @@
1010

1111

1212
class Cache_Version(Enum):
13-
# 系统用户
14-
TOKEN = "TOKEN"
13+
# 令牌
14+
TOKEN = "TOKEN", lambda token: token
15+
# 工作空间列表
16+
WORKSPACE_LIST = "WORKSPACE::LIST", lambda user_id: user_id
17+
# 用户数据
18+
USER = "USER", lambda user_id: user_id
19+
# 当前用户在当前工作空间的角色列表+本身的角色
20+
ROLE_LIST = "ROLE::LIST", lambda user_id, workspace_id: f"{user_id}::{workspace_id}"
21+
# 当前用户在当前工作空间的权限列表+本身的权限列表
22+
PERMISSION_LIST = "PERMISSION::LIST", lambda user_id, workspace_id: f"{user_id}::{workspace_id}"
23+
24+
25+
version, get_key = Cache_Version.TOKEN.value

Diff for: apps/common/constants/permission_constants.py

+41-18
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
from enum import Enum
99
from typing import List
1010

11-
from django.utils.translation import gettext_lazy as _
12-
1311

1412
class Group(Enum):
1513
"""
@@ -26,6 +24,10 @@ class Operate(Enum):
2624
EDIT = "EDIT"
2725
CREATE = "CREATE"
2826
DELETE = "DELETE"
27+
"""
28+
使用权限
29+
"""
30+
USE = "USE"
2931

3032

3133
class RoleGroup(Enum):
@@ -43,21 +45,34 @@ def __init__(self, name: str, decs: str, group: RoleGroup):
4345

4446

4547
class RoleConstants(Enum):
46-
ADMIN = Role(_("ADMIN"), _('Super administrator'), RoleGroup.SYSTEM_USER)
48+
ADMIN = Role("ADMIN", '超级管理员', RoleGroup.SYSTEM_USER)
49+
WORKSPACE_MANAGE = Role("WORKSPACE_MANAGE", '工作空间管理员', RoleGroup.SYSTEM_USER)
50+
USER = Role("USER", '普通用户', RoleGroup.SYSTEM_USER)
4751

4852

4953
class Permission:
5054
"""
5155
权限信息
5256
"""
5357

54-
def __init__(self, group: Group, operate: Operate, roles=None, dynamic_tag=None):
55-
if roles is None:
56-
roles = []
58+
def __init__(self, group: Group, operate: Operate, dynamic_tag=None, role_list=None):
59+
if role_list is None:
60+
role_list = []
5761
self.group = group
5862
self.operate = operate
59-
self.roleList = roles
6063
self.dynamic_tag = dynamic_tag
64+
# 用于获取角色与权限的关系,只适用于没有权限管理的
65+
self.role_list = role_list
66+
67+
@staticmethod
68+
def new_instance(permission_str: str):
69+
permission_split = permission_str.split(":")
70+
group = Group[permission_split[0]]
71+
operate = Operate[permission_split[2]]
72+
if len(permission_split) > 2:
73+
dynamic_tag = ":".join(permission_split[2:])
74+
return Permission(group, operate, dynamic_tag)
75+
return Permission(group, operate)
6176

6277
def __str__(self):
6378
return self.group.value + ":" + self.operate.value + (
@@ -71,19 +86,20 @@ class PermissionConstants(Enum):
7186
"""
7287
权限枚举
7388
"""
74-
USER_READ = Permission(group=Group.USER, operate=Operate.READ, roles=[RoleConstants.ADMIN])
75-
USER_EDIT = Permission(group=Group.USER, operate=Operate.EDIT, roles=[RoleConstants.ADMIN])
76-
USER_DELETE = Permission(group=Group.USER, operate=Operate.DELETE, roles=[RoleConstants.ADMIN])
89+
USER_READ = Permission(group=Group.USER, operate=Operate.READ, role_list=[RoleConstants.ADMIN,
90+
RoleConstants.USER])
91+
USER_EDIT = Permission(group=Group.USER, operate=Operate.EDIT, role_list=[RoleConstants.ADMIN])
92+
USER_DELETE = Permission(group=Group.USER, operate=Operate.DELETE, role_list=[RoleConstants.ADMIN])
7793

7894

79-
def get_permission_list_by_role(role: RoleConstants):
95+
def get_default_permission_list_by_role(role: RoleConstants):
8096
"""
8197
根据角色 获取角色对应的权限
8298
:param role: 角色
8399
:return: 权限
84100
"""
85101
return list(map(lambda k: PermissionConstants[k],
86-
list(filter(lambda k: PermissionConstants[k].value.roleList.__contains__(role),
102+
list(filter(lambda k: PermissionConstants[k].value.role_list.__contains__(role),
87103
PermissionConstants.__members__))))
88104

89105

@@ -92,14 +108,21 @@ class Auth:
92108
用于存储当前用户的角色和权限
93109
"""
94110

95-
def __init__(self, role_list: List[RoleConstants], permission_list: List[PermissionConstants | Permission]
96-
, client_id, client_type, current_role: RoleConstants, **keywords):
97-
self.role_list = role_list
111+
def __init__(self,
112+
work_space_list: List,
113+
current_workspace,
114+
current_role_list: List[Role],
115+
permission_list: List[PermissionConstants | Permission],
116+
**keywords):
117+
# 当前用户所有工作空间
118+
self.work_space_list = work_space_list
119+
# 当前工作空间
120+
self.current_workspace = current_workspace
121+
# 当前工作空间的所有权限+非工作空间权限
98122
self.permission_list = permission_list
99-
self.client_id = client_id
100-
self.client_type = client_type
123+
# 当前工作空间角色列表
124+
self.current_role_list = current_role_list
101125
self.keywords = keywords
102-
self.current_role = current_role
103126

104127

105128
class CompareConstants(Enum):

0 commit comments

Comments
 (0)