user_token.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. # coding=utf-8
  2. """
  3. @project: MaxKB
  4. @Author:虎虎
  5. @file: authenticate.py
  6. @date:2024/3/14 03:02
  7. @desc: 用户认证
  8. """
  9. from functools import reduce
  10. from typing import List
  11. from django.core.cache import cache
  12. from django.db.models import QuerySet
  13. from django.utils.translation import gettext_lazy as _
  14. from common.auth.handle.auth_base_handle import AuthBaseHandle
  15. from common.constants.authentication_type import AuthenticationType
  16. from common.constants.cache_version import Cache_Version
  17. from common.constants.permission_constants import Auth, PermissionConstants, ResourcePermissionGroup, \
  18. get_permission_list_by_resource_group, ResourceAuthType, \
  19. ResourcePermissionRole, get_default_role_permission_mapping_list, get_default_workspace_user_role_mapping_list, \
  20. RoleConstants, ResourcePermission, Resource, WorkspaceGroup
  21. from common.database_model_manage.database_model_manage import DatabaseModelManage
  22. from common.exception.app_exception import AppAuthenticationFailed
  23. from common.utils.common import group_by
  24. from maxkb.const import CONFIG
  25. from system_manage.models.workspace_user_permission import WorkspaceUserResourcePermission
  26. from users.models import User
  27. permission_constants_dict = {p.value.__str__(): p for p in PermissionConstants}
  28. def get_permission(permission_id):
  29. """
  30. 获取权限字符串
  31. @param permission_id: 权限id
  32. @return: 权限字符串
  33. """
  34. if isinstance(permission_id, PermissionConstants):
  35. permission_id = permission_id.value
  36. return f"{permission_id}"
  37. def get_workspace_permission(permission_id, workspace_id, role=None):
  38. """
  39. 获取工作空间权限字符串
  40. @param permission_id: 权限id
  41. @param workspace_id: 工作空间id
  42. @param role: 角色
  43. @return:
  44. """
  45. if isinstance(permission_id, PermissionConstants):
  46. permission_id = permission_id.value
  47. if role and role.type == RoleConstants.WORKSPACE_MANAGE.value.__str__():
  48. return [f"{permission_id}:/WORKSPACE/{workspace_id}:ROLE/{role.type}",
  49. f"{permission_id}:/WORKSPACE/{workspace_id}"]
  50. return [f"{permission_id}:/WORKSPACE/{workspace_id}"]
  51. def get_role_permission(role, workspace_id):
  52. """
  53. 获取工作空间角色
  54. @param role: 角色
  55. @param workspace_id: 工作空间id
  56. @return:
  57. """
  58. if isinstance(role, RoleConstants):
  59. role = role.value
  60. return f"{role}:/WORKSPACE/{workspace_id}"
  61. def get_workspace_permission_list(role_permission_mapping_dict, workspace_user_role_mapping_list, role_model_dict):
  62. """
  63. 获取工作空间下所有的权限
  64. @param role_permission_mapping_dict: 角色权限关联字典
  65. @param workspace_user_role_mapping_list: 工作空间用户角色关联列表
  66. @param role_model_dict: 角色字典
  67. @return: 工作空间下的权限
  68. """
  69. workspace_permission_list = [
  70. [get_workspace_permission(role_permission_mapping.permission_id, w_u_r.workspace_id,
  71. role_model_dict.get(w_u_r.role_id, None)) for role_permission_mapping
  72. in
  73. role_permission_mapping_dict.get(w_u_r.role_id, [])] for w_u_r in workspace_user_role_mapping_list]
  74. return reduce(lambda x, y: [*x, *y], reduce(lambda x, y: [*x, *y], workspace_permission_list, []), [])
  75. def get_workspace_resource_permission_list(
  76. workspace_user_resource_permission_list: List[WorkspaceUserResourcePermission],
  77. role_permission_mapping_dict,
  78. workspace_user_role_mapping_dict):
  79. """
  80. @param workspace_user_resource_permission_list: 工作空间用户资源权限列表
  81. @param role_permission_mapping_dict: 角色权限关联字典 key为role_id
  82. @param workspace_user_role_mapping_dict: 工作空间用户角色映射字典 key为role_id
  83. @return: 工作空间资源权限列表
  84. """
  85. resource_permission_list = [
  86. get_workspace_resource_permission_list_by_workspace_user_permission(workspace_user_resource_permission,
  87. role_permission_mapping_dict,
  88. workspace_user_role_mapping_dict) for
  89. workspace_user_resource_permission in workspace_user_resource_permission_list]
  90. # 将二维数组扁平为一维
  91. return reduce(lambda x, y: [*x, *y], resource_permission_list, [])
  92. def get_workspace_resource_permission_list_by_workspace_user_permission(
  93. workspace_user_resource_permission: WorkspaceUserResourcePermission,
  94. role_permission_mapping_dict,
  95. workspace_user_role_mapping_dict):
  96. """
  97. @param workspace_user_resource_permission: 工作空间用户资源权限对象
  98. @param role_permission_mapping_dict: 角色权限关联字典 key为role_id
  99. @param workspace_user_role_mapping_dict: 工作空间用户角色关联字典 key为role_id
  100. @return: 工作空间用户资源的权限列表
  101. """
  102. # 判断用户在当前工作空间是否为内置USER
  103. workspace_role_ids = [
  104. wur.role_id
  105. for wur in
  106. workspace_user_role_mapping_dict.get(workspace_user_resource_permission.workspace_id,[])
  107. ]
  108. is_builtin_user = RoleConstants.USER.value.__str__() in workspace_role_ids
  109. role_permission_mapping_list = [role_permission_mapping_dict.get(workspace_user_role_mapping.role_id, []) for
  110. workspace_user_role_mapping in
  111. workspace_user_role_mapping_dict.get(
  112. workspace_user_resource_permission.workspace_id)]
  113. role_permission_mapping_list = reduce(lambda x, y: [*x, *y], role_permission_mapping_list, [])
  114. # 如果是根据角色
  115. if (workspace_user_resource_permission.auth_type == ResourceAuthType.ROLE
  116. and workspace_user_resource_permission.permission_list.__contains__(
  117. ResourcePermissionRole.ROLE)):
  118. per_op_permissions = [
  119. f"{role_permission_mapping.permission_id}:/WORKSPACE/{workspace_user_resource_permission.workspace_id}/{workspace_user_resource_permission.auth_target_type}/{workspace_user_resource_permission.target}"
  120. for role_permission_mapping in role_permission_mapping_list if (permission_constants_dict.get(role_permission_mapping.permission_id).value.parent_group or []).__contains__(
  121. WorkspaceGroup(workspace_user_resource_permission.auth_target_type))]
  122. if is_builtin_user:
  123. per_op_permissions.append(
  124. f"{workspace_user_resource_permission.auth_target_type}:/WORKSPACE/{workspace_user_resource_permission.workspace_id}/{workspace_user_resource_permission.auth_target_type}/{workspace_user_resource_permission.target}"
  125. )
  126. return per_op_permissions
  127. elif workspace_user_resource_permission.auth_type == ResourceAuthType.RESOURCE_PERMISSION_GROUP:
  128. resource_permission_list = [
  129. [
  130. f"{permission}:/WORKSPACE/{workspace_user_resource_permission.workspace_id}/{workspace_user_resource_permission.auth_target_type}/{workspace_user_resource_permission.target}"
  131. for permission in get_permission_list_by_resource_group(
  132. ResourcePermissionGroup(Resource(workspace_user_resource_permission.auth_target_type),
  133. ResourcePermission(resource_permission)))]
  134. for resource_permission in workspace_user_resource_permission.permission_list if
  135. ResourcePermission.values.__contains__(resource_permission)]
  136. # 将二维数组扁平为一维
  137. return reduce(lambda x, y: [*x, *y], resource_permission_list, [])
  138. return []
  139. def get_permission_list(user,
  140. workspace_user_role_mapping_model,
  141. workspace_model,
  142. role_model,
  143. role_permission_mapping_model):
  144. user_id = user.id
  145. version = Cache_Version.PERMISSION_LIST.get_version()
  146. key = Cache_Version.PERMISSION_LIST.get_key(user_id=user_id)
  147. # 获取权限列表
  148. 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
  149. permission_list = cache.get(key, version=version)
  150. if permission_list is None:
  151. if is_query_model:
  152. # 获取工作空间 用户 角色映射数据
  153. workspace_user_role_mapping_list = QuerySet(workspace_user_role_mapping_model).filter(user_id=user_id)
  154. workspace_user_role_mapping_dict = group_by(workspace_user_role_mapping_list,
  155. lambda item: item.workspace_id)
  156. role_id_list = list(set([workspace_user_role_mapping.role_id for workspace_user_role_mapping in
  157. workspace_user_role_mapping_list]))
  158. # 获取角色权限映射数据
  159. role_permission_mapping_list = QuerySet(role_permission_mapping_model).filter(
  160. role_id__in=role_id_list)
  161. role_model_list = QuerySet(role_model).filter(id__in=role_id_list)
  162. role_model_dict = {role_model.id: role_model for role_model in role_model_list}
  163. role_permission_mapping_dict = group_by(
  164. role_permission_mapping_list, lambda item: item.role_id)
  165. workspace_user_permission_list = QuerySet(WorkspaceUserResourcePermission).filter(
  166. workspace_id__in=[workspace_user_role.workspace_id for workspace_user_role in
  167. workspace_user_role_mapping_list if
  168. (role_model_dict.get(workspace_user_role.role_id).type == 'USER' if
  169. role_model_dict.get(workspace_user_role.role_id) else False)],
  170. user_id=user_id)
  171. # 资源权限
  172. workspace_resource_permission_list = get_workspace_resource_permission_list(workspace_user_permission_list,
  173. role_permission_mapping_dict,
  174. workspace_user_role_mapping_dict)
  175. workspace_permission_list = get_workspace_permission_list(role_permission_mapping_dict,
  176. workspace_user_role_mapping_list, role_model_dict)
  177. # 系统权限
  178. system_permission_list = [role_permission_mapping.permission_id for role_permission_mapping in
  179. role_permission_mapping_list]
  180. # 合并权限
  181. permission_list = system_permission_list + workspace_permission_list + workspace_resource_permission_list
  182. permission_list = list(set(permission_list))
  183. cache.set(key, permission_list, version=version)
  184. else:
  185. workspace_id_list = ['default']
  186. workspace_user_resource_permission_list = QuerySet(WorkspaceUserResourcePermission).filter(
  187. workspace_id__in=workspace_id_list, user_id=user_id)
  188. role_permission_mapping_list = get_default_role_permission_mapping_list()
  189. role_permission_mapping_dict = group_by(role_permission_mapping_list, lambda item: item.role_id)
  190. workspace_user_role_mapping_list = get_default_workspace_user_role_mapping_list([user.role])
  191. workspace_user_role_mapping_dict = group_by(workspace_user_role_mapping_list,
  192. lambda item: item.workspace_id)
  193. # 资源权限
  194. workspace_resource_permission_list = get_workspace_resource_permission_list(
  195. workspace_user_resource_permission_list,
  196. role_permission_mapping_dict,
  197. workspace_user_role_mapping_dict)
  198. # 合并权限
  199. permission_list = workspace_resource_permission_list
  200. permission_list = list(set(permission_list))
  201. cache.set(key, permission_list, version=version)
  202. return permission_list
  203. system_role_list = [RoleConstants.ADMIN.value.name, RoleConstants.WORKSPACE_MANAGE.value.name,
  204. RoleConstants.USER.value.name]
  205. system_role = RoleConstants.ADMIN.value.name
  206. def reset_workspace_role(role_id, workspace_id, role_dict):
  207. if system_role_list.__contains__(role_id):
  208. if system_role == role_id:
  209. return [role_id]
  210. else:
  211. return [f"{role_id}:/WORKSPACE/{workspace_id}", role_id]
  212. else:
  213. r = role_dict.get(role_id)
  214. if r is None:
  215. return ''
  216. role_type = role_dict.get(role_id).type
  217. if system_role == role_type:
  218. return [RoleConstants.EXTENDS_ADMIN.value.name]
  219. return [f"EXTENDS_{role_type}:/WORKSPACE/{workspace_id}", f"EXTENDS_{role_type}"]
  220. def get_role_list(user,
  221. workspace_user_role_mapping_model,
  222. workspace_model,
  223. role_model,
  224. role_permission_mapping_model):
  225. """
  226. 获取当前用户的角色列表
  227. """
  228. version = Cache_Version.ROLE_LIST.get_version()
  229. key = Cache_Version.ROLE_LIST.get_key(user_id=user.id)
  230. workspace_list = cache.get(key, version=version)
  231. # 获取权限列表
  232. 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
  233. if workspace_list is None:
  234. if is_query_model:
  235. # 获取工作空间 用户 角色映射数据
  236. workspace_user_role_mapping_list = QuerySet(workspace_user_role_mapping_model).filter(user_id=user.id)
  237. role_list = QuerySet(role_model).filter(id__in=[wurm.role_id for wurm in workspace_user_role_mapping_list])
  238. role_dict = {r.id: r for r in role_list}
  239. role_list = list(
  240. set(reduce(lambda x, y: [*x, *y], [reset_workspace_role(workspace_user_role_mapping.role_id,
  241. workspace_user_role_mapping.workspace_id,
  242. role_dict)
  243. for
  244. workspace_user_role_mapping in
  245. workspace_user_role_mapping_list], [])))
  246. cache.set(key, workspace_list, version=version)
  247. return role_list
  248. else:
  249. if user.role == RoleConstants.ADMIN.value.__str__():
  250. role_list = [user.role, get_role_permission(RoleConstants.WORKSPACE_MANAGE, 'default')]
  251. else:
  252. role_list = [user.role, get_role_permission(RoleConstants.USER, 'default')]
  253. cache.set(key, role_list, version=version)
  254. return role_list
  255. return workspace_list
  256. def get_auth(user):
  257. workspace_user_role_mapping_model = DatabaseModelManage.get_model("workspace_user_role_mapping")
  258. workspace_model = DatabaseModelManage.get_model("workspace_model")
  259. role_model = DatabaseModelManage.get_model("role_model")
  260. role_permission_mapping_model = DatabaseModelManage.get_model("role_permission_mapping_model")
  261. permission_list = get_permission_list(user, workspace_user_role_mapping_model, workspace_model,
  262. role_model, role_permission_mapping_model)
  263. role_list = get_role_list(user, workspace_user_role_mapping_model, workspace_model,
  264. role_model, role_permission_mapping_model)
  265. return Auth(role_list, permission_list)
  266. class UserToken(AuthBaseHandle):
  267. def support(self, request, token: str, get_token_details):
  268. auth_details = get_token_details()
  269. if auth_details is None:
  270. return False
  271. return 'id' in auth_details and auth_details.get('type') == AuthenticationType.SYSTEM_USER.value
  272. def handle(self, request, token: str, get_token_details):
  273. version, get_key = Cache_Version.TOKEN.value
  274. cache_token = cache.get(get_key(token), version=version)
  275. if cache_token is None:
  276. raise AppAuthenticationFailed(1002, _('Login expired'))
  277. auth_details = get_token_details()
  278. timeout = CONFIG.get_session_timeout()
  279. cache.touch(get_key(token), timeout=timeout, version=version)
  280. user = QuerySet(User).get(id=auth_details['id'])
  281. if not user.is_active or user.password != cache_token.password:
  282. raise AppAuthenticationFailed(1002, _('Authentication information is incorrect'))
  283. auth = get_auth(user)
  284. return user, auth