nc-user-terminator 0.1.4__tar.gz → 0.1.5__tar.gz

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.

Potentially problematic release.


This version of nc-user-terminator might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nc-user-terminator
3
- Version: 0.1.4
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,3 @@
1
+ # 更新
2
+ + V0.1.5
3
+ - 新增本地缓存机制
@@ -7,7 +7,7 @@ from exceptions import OAuthError
7
7
  from utils import request
8
8
 
9
9
 
10
- TENANT_HEADER = "X-Tenant-Code"
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
- tenant_code: str,
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 tenant_code: 租户编码
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._tenant_code = tenant_code
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 = {TENANT_HEADER: self._tenant_code}
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
- self._cache_user(token, res_dict)
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
+
@@ -0,0 +1,77 @@
1
+ import json
2
+ import urllib.parse
3
+ import urllib.request
4
+ import urllib.error
5
+ from typing import Optional, Dict, Any
6
+
7
+
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
+ """
25
+ # 拼接 GET 参数
26
+ if params:
27
+ query = urllib.parse.urlencode(params)
28
+ url = f"{url}?{query}"
29
+
30
+ data = None
31
+ if json_body is not None:
32
+ data = json.dumps(json_body).encode("utf-8")
33
+ if headers is None:
34
+ headers = {}
35
+ headers["Content-Type"] = "application/json"
36
+
37
+ req = urllib.request.Request(url, method=method.upper(), data=data)
38
+ if headers:
39
+ for k, v in headers.items():
40
+ req.add_header(k, v)
41
+
42
+ result = {
43
+ "status": 0,
44
+ "success": False,
45
+ "message": None,
46
+ "error": None
47
+ }
48
+
49
+ try:
50
+ with urllib.request.urlopen(req) as resp:
51
+ body = resp.read().decode()
52
+ if not body:
53
+ return {}
54
+ try:
55
+ return json.loads(body)
56
+ except json.JSONDecodeError:
57
+ result["status"] = 200
58
+ result["success"] = False
59
+ result["message"] = body
60
+ result["error"] = "Invalid JSON response"
61
+ return result
62
+ except urllib.error.HTTPError as e:
63
+ body = e.read().decode() if e.fp else None
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
71
+ except urllib.error.URLError as e:
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.4
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
+ - 新增本地缓存机制
@@ -4,11 +4,12 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "nc-user-terminator"
7
- version = "0.1.4"
7
+ version = "0.1.5"
8
8
  description = "OAuth client wrapper for multi-tenant projects"
9
9
  authors = [
10
10
  { name = "bw_song" }
11
11
  ]
12
+ readme = "README.md"
12
13
  requires-python = ">=3.8"
13
14
  dependencies = [
14
15
  "cachetools==6.2.0"
File without changes
@@ -1,39 +0,0 @@
1
- import json
2
- import urllib.parse
3
- import urllib.request
4
- import urllib.error
5
-
6
- from exceptions import OAuthError
7
-
8
-
9
- def request(method: str, url: str, params=None, headers=None, json_body=None) -> dict:
10
- # 拼接 GET 参数
11
- if params:
12
- query = urllib.parse.urlencode(params)
13
- url = f"{url}?{query}"
14
-
15
- data = None
16
- if json_body is not None:
17
- data = json.dumps(json_body).encode("utf-8")
18
- if headers is None:
19
- headers = {}
20
- headers["Content-Type"] = "application/json"
21
-
22
- req = urllib.request.Request(url, method=method.upper(), data=data)
23
-
24
- if headers:
25
- for k, v in headers.items():
26
- req.add_header(k, v)
27
-
28
- try:
29
- with urllib.request.urlopen(req) as resp:
30
- body = resp.read().decode()
31
- try:
32
- return json.loads(body)
33
- except json.JSONDecodeError:
34
- raise OAuthError("Invalid JSON response", resp.getcode(), body)
35
- except urllib.error.HTTPError as e:
36
- body = e.read().decode() if e.fp else None
37
- raise OAuthError("HTTP request failed", e.code, body)
38
- except urllib.error.URLError as e:
39
- raise OAuthError(f"Network error: {e.reason}")