Skip to content

Commit 6397ec3

Browse files
committed
feat: Optimize interface authentication logic
1 parent c6b75e0 commit 6397ec3

13 files changed

Lines changed: 239 additions & 297 deletions

File tree

‎apps/chat/serializers/chat_authentication.py‎

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from rest_framework import serializers
1616

1717
from application.models import ApplicationAccessToken, Application, ApplicationVersion
18-
from common.auth.common import FileToken, ChatToken
18+
from common.auth.common import ChatToken
1919
from common.auth.constants.operate_constants import Operate
2020
from common.constants.authentication_type import AuthenticationType
2121
from common.constants.cache_version import Cache_Version
@@ -48,14 +48,10 @@ def auth(self, request):
4848
if application_access_token is None or not application_access_token.is_active:
4949
raise AppApiException(500, _("Invalid application_id"))
5050
application_id = str(application_id)
51-
return (
52-
ChatToken(chat_user_id, _type, str(Operate.ANNOTATION_AUTH), application_id=application_id).to_token(),
53-
FileToken(chat_user_id, _type, application_id=application_id).to_token(),
54-
)
55-
return (
56-
ChatToken(chat_user_id, _type, str(Operate.ANNOTATION_AUTH)).to_token(),
57-
FileToken(chat_user_id, _type).to_token(),
58-
)
51+
return ChatToken(
52+
chat_user_id, _type, str(Operate.ANNOTATION_AUTH), application_id=application_id
53+
).to_token()
54+
return (ChatToken(chat_user_id, _type, str(Operate.ANNOTATION_AUTH)).to_token(),)
5955

6056

6157
class AnonymousAuthenticationV2Serializer(serializers.Serializer):

‎apps/chat/views/v2/chat.py‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,9 @@
4343
)
4444
from common.auth import ChatTokenAuth
4545
from common.auth.authentication import has_permissions
46-
from common.auth.common import FileToken
4746
from common.auth.constants.chat_permission_constants import ChatPermissionConstants
4847
from common.constants.authentication_type import AuthenticationType
4948
from common.constants.cache_version import Cache_Version
50-
from common.auth.common import ChatAuthentication
5149
from common.exception.app_exception import AppAuthenticationFailed, AppApiException
5250
from common.log.log import _get_ip_address, log
5351
from common.result import result
@@ -443,7 +441,7 @@ def create_token_and_cache(access_token, user, request):
443441
token = ChatUserAccessTokenSerializer.create_token_and_cache(access_token, user, request)
444442
version, get_key = Cache_Version.CHAT_USER_TOKEN.value
445443
cache.set(get_key(token), user, timeout=60 * 60 * 2, version=version)
446-
return token, FileToken(str(user.id), AuthenticationType.CHAT_USER.value).to_token()
444+
return token
447445

448446
@classmethod
449447
def generate(self, request, f_token: str, response: HttpResponse, path: str = "/chat"):
@@ -474,9 +472,9 @@ class LocalLoginView(BaseAuthView):
474472
def post(self, request: Request, access_token: str = None):
475473
user = ChatUserAccessTokenSerializer.local_login(request.data, access_token)
476474
user.source = "LOCAL"
477-
token, f_token = self.create_token_and_cache(access_token, user, request)
475+
token = self.create_token_and_cache(access_token, user, request)
478476
response = result.success({"token": token})
479-
return self.generate(request, f_token, response, path=f"/chat/{access_token}/")
477+
return self.generate(request, token, response, path=f"/chat/{access_token}/")
480478

481479

482480
class Logout(APIView):

‎apps/chat/views/v3/chat.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
)
3939
from common.auth import ChatTokenAuth
4040
from common.auth.authentication import has_permissions
41-
from common.auth.common import FileToken, ChatToken
41+
from common.auth.common import ChatToken
4242
from common.auth.constants.chat_permission_constants import ChatPermissionConstants
4343
from common.auth.constants.operate_constants import Operate
4444
from common.constants.authentication_type import AuthenticationType
@@ -140,7 +140,7 @@ def options(self, request, *args, **kwargs):
140140
def post(self, request: Request):
141141
serializer = AnonymousAuthenticationSerializer(data=request.query_params)
142142
serializer.is_valid(raise_exception=True)
143-
token, f_token = serializer.auth(request)
143+
token = serializer.auth(request)
144144
response = result.success(
145145
token,
146146
headers={
@@ -156,7 +156,7 @@ def post(self, request: Request):
156156
cookie_path = f"{CONFIG.get_chat_path()}/{application_id}" if application_id else CONFIG.get_chat_path()
157157
response.set_cookie(
158158
key="mk_file_auth",
159-
value=f_token,
159+
value=token,
160160
max_age=7 * 24 * 3600,
161161
path=cookie_path,
162162
secure=is_https,
@@ -450,7 +450,7 @@ def create_token_and_cache(user, access_token, operate):
450450
).to_token()
451451
version, get_key = Cache_Version.CHAT_USER_TOKEN.value
452452
cache.set(get_key(token), user, timeout=60 * 60 * 2, version=version)
453-
return token, FileToken(str(user.id), AuthenticationType.CHAT_USER.value).to_token()
453+
return token
454454

455455
@classmethod
456456
def generate(self, request, f_token: str, response: HttpResponse, path: str = "/chat"):
@@ -482,9 +482,9 @@ def post(self, request: Request):
482482
user = ChatUserAccessTokenV3Serializer.local_login(request.data)
483483
user.source = "LOCAL"
484484
access_token = request.query_params.get("accessToken")
485-
token, f_token = self.create_token_and_cache(user, access_token, Operate.LOCAL)
485+
token = self.create_token_and_cache(user, access_token, Operate.LOCAL)
486486
response = result.success({"token": token})
487-
return self.generate(request, f_token, response, path=f"/chat/{access_token + '/' if access_token else ''}")
487+
return self.generate(request, token, response, path=f"/chat/{access_token + '/' if access_token else ''}")
488488

489489

490490
class Logout(APIView):

‎apps/common/auth/common.py‎

Lines changed: 28 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -7,138 +7,57 @@
77
@desc:
88
"""
99

10-
import hashlib
11-
import json
12-
import threading
10+
from django.core import signing
1311

14-
from django.core import signing, cache
15-
16-
from application.models import ChatUserType
1712
from common.constants.authentication_type import AuthenticationType
18-
from common.constants.cache_version import Cache_Version
19-
from common.utils.rsa_util import encrypt, decrypt
20-
21-
authentication_cache = cache.cache
22-
lock = threading.Lock()
23-
24-
25-
def _decrypt(authentication: str):
26-
cache_key = hashlib.sha256(authentication.encode()).hexdigest()
27-
result = authentication_cache.get(key=cache_key, version=Cache_Version.CHAT.value)
28-
if result is None:
29-
with lock:
30-
result = authentication_cache.get(cache_key, version=Cache_Version.CHAT.value)
31-
if result is None:
32-
result = decrypt(authentication)
33-
authentication_cache.set(cache_key, result, version=Cache_Version.CHAT.value, timeout=60 * 60 * 2)
34-
35-
return result
36-
37-
38-
class ChatAuthentication:
39-
def __init__(self, auth_type: str | None, **kwargs):
40-
self.auth_type = auth_type
41-
for k, v in kwargs.items():
42-
self.__setattr__(k, v)
43-
44-
def to_dict(self):
45-
return self.__dict__
46-
47-
def to_string(self):
48-
value = json.dumps(self.to_dict())
49-
authentication = encrypt(value)
50-
cache_key = hashlib.sha256(authentication.encode()).hexdigest()
51-
authentication_cache.set(cache_key, value, version=Cache_Version.CHAT.get_version(), timeout=60 * 60 * 2)
52-
return authentication
53-
54-
@staticmethod
55-
def new_instance(authentication: str):
56-
auth = json.loads(_decrypt(authentication))
57-
return ChatAuthentication(**auth)
13+
from common.exception.app_exception import AppAuthenticationFailed
5814

5915

60-
class FileToken:
61-
def __init__(self, user_id, _type, application_id: str = None):
62-
self.user_id = user_id
16+
class SystemToken:
17+
def __init__(self, user_id, _type: AuthenticationType, **kwargs):
18+
self.id = user_id
6319
self.type = _type
64-
self.application_id = application_id
65-
66-
def to_dict(self):
67-
return (
68-
{"user_id": self.user_id, "type": str(self.type), "application_id": self.application_id}
69-
if self.application_id
70-
else {"user_id": self.user_id, "type": str(self.type)}
71-
)
72-
73-
def to_token(self):
74-
return signing.dumps(self.to_dict())
75-
76-
@staticmethod
77-
def new_instance(token):
78-
token_dict = signing.loads(token)
79-
return FileToken(token_dict.get("user_id"), token_dict.get("type"), token_dict.get("application_id"))
80-
81-
82-
class ChatUserToken:
83-
def __init__(
84-
self,
85-
application_id,
86-
user_id,
87-
access_token,
88-
_type,
89-
chat_user_type,
90-
chat_user_id,
91-
authentication: ChatAuthentication,
92-
):
93-
self.application_id = application_id
94-
self.user_id = user_id
95-
self.access_token = access_token
96-
self.type = _type
97-
self.chat_user_type = chat_user_type
98-
self.chat_user_id = chat_user_id
99-
self.authentication = authentication
20+
self.kwargs = kwargs
10021

10122
def to_dict(self):
102-
return {
103-
"application_id": str(self.application_id),
104-
"user_id": str(self.user_id),
105-
"access_token": self.access_token,
106-
"type": str(self.type.value),
107-
"chat_user_type": str(self.chat_user_type),
108-
"chat_user_id": str(self.chat_user_id),
109-
"authentication": self.authentication.to_string(),
110-
}
23+
if self.kwargs:
24+
return {"user_id": self.id, "type": str(self.type.value), "kwargs": self.kwargs}
25+
return {"id": str(self.id), "type": str(self.type.value)}
11126

11227
def to_token(self):
11328
return signing.dumps(self.to_dict())
11429

115-
@staticmethod
116-
def new_instance(token_dict):
117-
return ChatUserToken(
118-
token_dict.get("application_id"),
119-
token_dict.get("user_id"),
120-
token_dict.get("access_token"),
121-
token_dict.get("type"),
122-
token_dict.get("chat_user_type"),
123-
token_dict.get("chat_user_id"),
124-
ChatAuthentication.new_instance(token_dict.get("authentication")),
125-
)
126-
12730

12831
class ChatToken:
12932
def __init__(self, user_id, _type: AuthenticationType, login_type: str, **kwargs):
130-
self.user_id = user_id
33+
self.id = user_id
13134
self.type = _type
13235
self.login_type = login_type
13336
self.kwargs = kwargs
13437

13538
def to_dict(self):
39+
if self.kwargs:
40+
return {
41+
"id": str(self.id),
42+
"type": str(self.type.value),
43+
"login_type": str(self.login_type),
44+
"kwargs": self.kwargs,
45+
}
13646
return {
137-
"user_id": str(self.user_id),
47+
"id": str(self.id),
13848
"type": str(self.type.value),
13949
"login_type": str(self.login_type),
140-
"kwargs": self.kwargs,
14150
}
14251

14352
def to_token(self):
14453
return signing.dumps(self.to_dict())
54+
55+
56+
def parse_token(token):
57+
details = signing.loads(token)
58+
_type = details.get("type")
59+
if _type:
60+
if _type == AuthenticationType.SYSTEM_USER.value:
61+
return SystemToken(details.get("id"), details.get("type"), **details.get("kwargs", {}))
62+
return ChatToken(details.get("id"), details.get("type"), details.get("login_type"), **details.get("kwargs", {}))
63+
raise AppAuthenticationFailed(1001, "")

‎apps/common/auth/constants/chat_permission_constants.py‎

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# coding=utf-8
22
"""
3-
@project: MaxKB
4-
@Author:虎虎虎
5-
@file: chat_permission_constants.py
6-
@date:2026/8/6 16:38
7-
@desc:
3+
@project: MaxKB
4+
@Author:虎虎虎
5+
@file: chat_permission_constants.py
6+
@date:2026/8/6 16:38
7+
@desc:
88
"""
9+
910
from enum import Enum
1011

1112
from common.auth.constants.group_constants import Group
@@ -16,34 +17,36 @@
1617

1718
class ChatPermissionConstants(Enum):
1819
CHAT_USER_ANONYMOUS = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.ANNOTATION_AUTH, 0)
19-
CHAT_USER_PASSWORD = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.PASSWORD, 1)
20-
CHAT_USER_LOCAL = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.LOCAL, 2)
21-
CHAT_USER_CAS = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.CAS, 3)
22-
CHAT_USER_DINGTALK = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.DINGTALK, 4)
23-
CHAT_USER_WECOM = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.WECOM, 5)
24-
CHAT_USER_LARK = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.LARK, 6)
25-
CHAT_USER_OIDC = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.OIDC, 7)
26-
CHAT_USER_LDAP = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.LDAP, 8)
27-
CHAT_USER_OAUTH2 = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.OAUTH2, 9)
20+
CHAT_USER_LOCAL = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.LOCAL, 1)
21+
CHAT_USER_CAS = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.CAS, 2)
22+
CHAT_USER_DINGTALK = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.DINGTALK, 3)
23+
CHAT_USER_WECOM = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.WECOM, 4)
24+
CHAT_USER_LARK = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.LARK, 5)
25+
CHAT_USER_OIDC = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.OIDC, 6)
26+
CHAT_USER_LDAP = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.LDAP, 7)
27+
CHAT_USER_OAUTH2 = Permission(Group.CHAT_USER, Group.CHAT_USER, Operate.OAUTH2, 8)
2828

2929
def get_permission(self):
30-
return self._build_workspace_permission('application_id')
30+
return self._build_workspace_permission("application_id")
3131

3232
def _build_workspace_permission(self, resource_id_key=None):
3333
def permission_factory(_, **kwargs):
34-
return Permission(group=self.value.group,
35-
sub_group=self.value.sub_group,
36-
operate=self.value.operate,
37-
bit_index=self.value.bit_index,
38-
workspace_id=kwargs.get('workspace_id'),
39-
resource_id=kwargs.get(resource_id_key) if resource_id_key else None)
34+
return Permission(
35+
group=self.value.group,
36+
sub_group=self.value.sub_group,
37+
operate=self.value.operate,
38+
bit_index=self.value.bit_index,
39+
workspace_id=kwargs.get("workspace_id"),
40+
resource_id=kwargs.get(resource_id_key) if resource_id_key else None,
41+
)
4042

4143
return permission_factory
4244

4345
@staticmethod
4446
def get_aggregate_permissions():
4547
return AggregatePermission(
46-
permissions=[_permission.get_permission() for _permission in ChatPermissionConstants])
48+
permissions=[_permission.get_permission() for _permission in ChatPermissionConstants]
49+
)
4750

4851

4952
# 权限字符串与权限对象的Map

0 commit comments

Comments
 (0)