nc-user-terminator 0.1.4__py3-none-any.whl → 0.1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nc_user_manager/client.py +36 -7
- nc_user_manager/utils.py +45 -7
- {nc_user_terminator-0.1.4.dist-info → nc_user_terminator-0.1.5.dist-info}/METADATA +5 -2
- nc_user_terminator-0.1.5.dist-info/RECORD +10 -0
- nc_user_terminator-0.1.4.dist-info/RECORD +0 -10
- {nc_user_terminator-0.1.4.dist-info → nc_user_terminator-0.1.5.dist-info}/WHEEL +0 -0
- {nc_user_terminator-0.1.4.dist-info → nc_user_terminator-0.1.5.dist-info}/top_level.txt +0 -0
nc_user_manager/client.py
CHANGED
|
@@ -7,7 +7,7 @@ from exceptions import OAuthError
|
|
|
7
7
|
from utils import request
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
PRODUCT_HEADER = "X-Product-Code"
|
|
11
11
|
DEFAULT_TTL = 3600
|
|
12
12
|
|
|
13
13
|
|
|
@@ -15,7 +15,7 @@ class OAuthClient:
|
|
|
15
15
|
def __init__(
|
|
16
16
|
self,
|
|
17
17
|
base_url: str,
|
|
18
|
-
|
|
18
|
+
product_code: str,
|
|
19
19
|
redirect_url: Optional[str] = None,
|
|
20
20
|
single_session: bool = False,
|
|
21
21
|
cache: Optional[BaseCache] = None,
|
|
@@ -24,12 +24,12 @@ class OAuthClient:
|
|
|
24
24
|
OAuth 客户端
|
|
25
25
|
|
|
26
26
|
:param base_url: 服务端基础地址 (例如 http://localhost:8000)
|
|
27
|
-
:param
|
|
27
|
+
:param product_code: 产品编码
|
|
28
28
|
:param redirect_url: 可选,重定向地址
|
|
29
29
|
:param single_session: 是否单会话登录
|
|
30
30
|
"""
|
|
31
31
|
self._base_url = base_url.rstrip("/")
|
|
32
|
-
self.
|
|
32
|
+
self._product_code = product_code
|
|
33
33
|
self._redirect_url = redirect_url
|
|
34
34
|
self._single_session = single_session
|
|
35
35
|
self._cache = cache or MemoryCache(maxsize=10000, ttl=DEFAULT_TTL)
|
|
@@ -43,7 +43,7 @@ class OAuthClient:
|
|
|
43
43
|
return await asyncio.to_thread(request, *args, **kwargs)
|
|
44
44
|
|
|
45
45
|
def _headers(self, extra: Optional[Dict[str, str]] = None) -> Dict[str, str]:
|
|
46
|
-
headers = {
|
|
46
|
+
headers = {PRODUCT_HEADER: self._product_code}
|
|
47
47
|
if extra:
|
|
48
48
|
headers.update(extra)
|
|
49
49
|
return headers
|
|
@@ -209,7 +209,8 @@ class OAuthClient:
|
|
|
209
209
|
headers = self._headers({"Authorization": f"Bearer {token}"})
|
|
210
210
|
res_dict = request("GET", f"{self._base_url}/api/me", headers=headers)
|
|
211
211
|
|
|
212
|
-
|
|
212
|
+
if res_dict.get("success", True):
|
|
213
|
+
self._cache_user(token, res_dict)
|
|
213
214
|
return UserResponse(res_dict)
|
|
214
215
|
|
|
215
216
|
async def say_my_name_async(self, token: str) -> UserResponse:
|
|
@@ -224,8 +225,9 @@ class OAuthClient:
|
|
|
224
225
|
|
|
225
226
|
headers = self._headers({"Authorization": f"Bearer {token}"})
|
|
226
227
|
res_dict = await self._arequest("GET", f"{self._base_url}/api/me", headers=headers)
|
|
228
|
+
if res_dict.get("success", True):
|
|
229
|
+
await self._cache_user_async(token, res_dict)
|
|
227
230
|
|
|
228
|
-
await self._cache_user_async(token, res_dict)
|
|
229
231
|
return UserResponse(res_dict)
|
|
230
232
|
|
|
231
233
|
# 刷新过期时间
|
|
@@ -264,3 +266,30 @@ class OAuthClient:
|
|
|
264
266
|
await self._uncache_user_async(token, data)
|
|
265
267
|
return resp
|
|
266
268
|
|
|
269
|
+
async def main():
|
|
270
|
+
def get_redis_url() -> str:
|
|
271
|
+
return f'redis://default:1q2w3e@localhost:6379/1'
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
import redis.asyncio as redis
|
|
275
|
+
# —— Redis 连接与策略(Bearer + Redis)——
|
|
276
|
+
_redis = redis.from_url(get_redis_url(), decode_responses=True)
|
|
277
|
+
|
|
278
|
+
redis_cache = AsyncRedisCache(_redis)
|
|
279
|
+
|
|
280
|
+
client = OAuthClient("http://localhost:8000/", "bankgpt", "http://localhost:8000/auth/google/custom_callback", single_session=True, cache=redis_cache)
|
|
281
|
+
# authorize = client.authorize("google")
|
|
282
|
+
# print(authorize)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
name = await client.say_my_name_async("Tu72u4SVue4ezadi1v5Ui9r9HjxH7YqbkY_yf5jFtPQ")
|
|
286
|
+
print(name)
|
|
287
|
+
name = await client.say_my_name_async("Tu72u4SVue4ezadi1v5Ui9r9HjxH7YqbkY_yf5jFtPQ")
|
|
288
|
+
print(name)
|
|
289
|
+
name = await client.logout_async("Tu72u4SVue4ezadi1v5Ui9r9HjxH7YqbkY_yf5jFtPQ")
|
|
290
|
+
print(name)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
if __name__ == '__main__':
|
|
294
|
+
asyncio.run(main())
|
|
295
|
+
|
nc_user_manager/utils.py
CHANGED
|
@@ -2,11 +2,26 @@ import json
|
|
|
2
2
|
import urllib.parse
|
|
3
3
|
import urllib.request
|
|
4
4
|
import urllib.error
|
|
5
|
+
from typing import Optional, Dict, Any
|
|
5
6
|
|
|
6
|
-
from exceptions import OAuthError
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
def request(
|
|
9
|
+
method: str,
|
|
10
|
+
url: str,
|
|
11
|
+
params: Optional[Dict[str, Any]] = None,
|
|
12
|
+
headers: Optional[Dict[str, str]] = None,
|
|
13
|
+
json_body: Optional[dict] = None
|
|
14
|
+
) -> dict:
|
|
15
|
+
"""
|
|
16
|
+
发送 HTTP 请求并返回统一结果,不抛异常
|
|
17
|
+
返回格式:
|
|
18
|
+
{
|
|
19
|
+
"status": int, # HTTP 状态码
|
|
20
|
+
"success": bool, # 是否成功 (2xx)
|
|
21
|
+
"body": dict or str, # JSON解析后的body, 或原始body
|
|
22
|
+
"error": Optional[str] # 错误信息
|
|
23
|
+
}
|
|
24
|
+
"""
|
|
10
25
|
# 拼接 GET 参数
|
|
11
26
|
if params:
|
|
12
27
|
query = urllib.parse.urlencode(params)
|
|
@@ -20,20 +35,43 @@ def request(method: str, url: str, params=None, headers=None, json_body=None) ->
|
|
|
20
35
|
headers["Content-Type"] = "application/json"
|
|
21
36
|
|
|
22
37
|
req = urllib.request.Request(url, method=method.upper(), data=data)
|
|
23
|
-
|
|
24
38
|
if headers:
|
|
25
39
|
for k, v in headers.items():
|
|
26
40
|
req.add_header(k, v)
|
|
27
41
|
|
|
42
|
+
result = {
|
|
43
|
+
"status": 0,
|
|
44
|
+
"success": False,
|
|
45
|
+
"message": None,
|
|
46
|
+
"error": None
|
|
47
|
+
}
|
|
48
|
+
|
|
28
49
|
try:
|
|
29
50
|
with urllib.request.urlopen(req) as resp:
|
|
30
51
|
body = resp.read().decode()
|
|
52
|
+
if not body:
|
|
53
|
+
return {}
|
|
31
54
|
try:
|
|
32
55
|
return json.loads(body)
|
|
33
56
|
except json.JSONDecodeError:
|
|
34
|
-
|
|
57
|
+
result["status"] = 200
|
|
58
|
+
result["success"] = False
|
|
59
|
+
result["message"] = body
|
|
60
|
+
result["error"] = "Invalid JSON response"
|
|
61
|
+
return result
|
|
35
62
|
except urllib.error.HTTPError as e:
|
|
36
63
|
body = e.read().decode() if e.fp else None
|
|
37
|
-
|
|
64
|
+
result["status"] = e.code
|
|
65
|
+
try:
|
|
66
|
+
result["message"] = json.loads(body) if body else None
|
|
67
|
+
except json.JSONDecodeError:
|
|
68
|
+
result["message"] = body
|
|
69
|
+
result["error"] = "HTTPError"
|
|
70
|
+
result["success"] = False
|
|
38
71
|
except urllib.error.URLError as e:
|
|
39
|
-
|
|
72
|
+
result["status"] = 0
|
|
73
|
+
result["message"] = None
|
|
74
|
+
result["error"] = f"NetworkError: {e.reason}"
|
|
75
|
+
result["success"] = False
|
|
76
|
+
|
|
77
|
+
return result
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nc-user-terminator
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: OAuth client wrapper for multi-tenant projects
|
|
5
5
|
Author: bw_song
|
|
6
6
|
Author-email: m132777096902@gmail.com
|
|
@@ -8,5 +8,8 @@ Requires-Python: >=3.8
|
|
|
8
8
|
Description-Content-Type: text/markdown
|
|
9
9
|
Requires-Dist: cachetools==6.2.0
|
|
10
10
|
Dynamic: author-email
|
|
11
|
-
Dynamic: description-content-type
|
|
12
11
|
Dynamic: requires-python
|
|
12
|
+
|
|
13
|
+
# 更新
|
|
14
|
+
+ V0.1.5
|
|
15
|
+
- 新增本地缓存机制
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
nc_user_manager/__init__.py,sha256=fF3FZD0XUW5YCfTbBeJs3RK-Mnm3IQ7lns6Eb_tMqPU,238
|
|
2
|
+
nc_user_manager/cache.py,sha256=u9ioXDwHmEJHRB4VKI4JU_pp-8Y5O4bLPm8-pwqiMVc,2273
|
|
3
|
+
nc_user_manager/client.py,sha256=71pQ_4YZy1f_BJ9Pc2Md1r57SStqI1qRxnXU9IGAm5Y,11276
|
|
4
|
+
nc_user_manager/exceptions.py,sha256=yUMDrh1HHZF36UUadQNHvJlDgEYSYoYOObs8Q11fjrE,351
|
|
5
|
+
nc_user_manager/models.py,sha256=mDK7zskIcaThxvUUTWVf6eMasw7YaA3hDGVVSd1ZJgo,1088
|
|
6
|
+
nc_user_manager/utils.py,sha256=gxFSaUq0oiymIlvHITu2L7EkU2ZYQmW2q_okmUxGBeU,2319
|
|
7
|
+
nc_user_terminator-0.1.5.dist-info/METADATA,sha256=1uCPVZ-m6nHokYebpNHDAdgJbtNxxJxugWNvzmqxm1U,378
|
|
8
|
+
nc_user_terminator-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
9
|
+
nc_user_terminator-0.1.5.dist-info/top_level.txt,sha256=kOAUtl6RYo-x3vMJL8It3KCJLoIFPvMUiAAyXjPQTYA,16
|
|
10
|
+
nc_user_terminator-0.1.5.dist-info/RECORD,,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
nc_user_manager/__init__.py,sha256=fF3FZD0XUW5YCfTbBeJs3RK-Mnm3IQ7lns6Eb_tMqPU,238
|
|
2
|
-
nc_user_manager/cache.py,sha256=u9ioXDwHmEJHRB4VKI4JU_pp-8Y5O4bLPm8-pwqiMVc,2273
|
|
3
|
-
nc_user_manager/client.py,sha256=jCtHW65Hk3AV3VQaKj7QapCyLgKqDoHKuX3FKVtwZn4,10241
|
|
4
|
-
nc_user_manager/exceptions.py,sha256=yUMDrh1HHZF36UUadQNHvJlDgEYSYoYOObs8Q11fjrE,351
|
|
5
|
-
nc_user_manager/models.py,sha256=mDK7zskIcaThxvUUTWVf6eMasw7YaA3hDGVVSd1ZJgo,1088
|
|
6
|
-
nc_user_manager/utils.py,sha256=0QmJ9s3mzuYQSlwkcS8BW5XCe23lcoKskEeuqfdZHck,1245
|
|
7
|
-
nc_user_terminator-0.1.4.dist-info/METADATA,sha256=-fUx3iRGBFFT3AqVd69tATCupipDXL7dVzHTQ6R_oFw,361
|
|
8
|
-
nc_user_terminator-0.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
9
|
-
nc_user_terminator-0.1.4.dist-info/top_level.txt,sha256=kOAUtl6RYo-x3vMJL8It3KCJLoIFPvMUiAAyXjPQTYA,16
|
|
10
|
-
nc_user_terminator-0.1.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|