nc-user-terminator 0.1.5__py3-none-any.whl → 0.1.17__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 +150 -22
- nc_user_manager/models.py +8 -4
- nc_user_manager/utils.py +10 -1
- nc_user_terminator-0.1.17.dist-info/METADATA +44 -0
- nc_user_terminator-0.1.17.dist-info/RECORD +10 -0
- nc_user_terminator-0.1.5.dist-info/METADATA +0 -15
- nc_user_terminator-0.1.5.dist-info/RECORD +0 -10
- {nc_user_terminator-0.1.5.dist-info → nc_user_terminator-0.1.17.dist-info}/WHEEL +0 -0
- {nc_user_terminator-0.1.5.dist-info → nc_user_terminator-0.1.17.dist-info}/top_level.txt +0 -0
nc_user_manager/client.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from typing import Optional, Dict, Any
|
|
3
3
|
|
|
4
|
-
from cache import MemoryCache, BaseCache, AsyncRedisCache
|
|
5
|
-
from models import UserResponse, OAuth2AuthorizeResponse, CallbackResponse
|
|
6
|
-
from exceptions import OAuthError
|
|
7
|
-
from utils import request
|
|
4
|
+
from nc_user_manager.cache import MemoryCache, BaseCache, AsyncRedisCache
|
|
5
|
+
from nc_user_manager.models import UserResponse, OAuth2AuthorizeResponse, CallbackResponse
|
|
6
|
+
from nc_user_manager.exceptions import OAuthError
|
|
7
|
+
from nc_user_manager.utils import request
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
PRODUCT_HEADER = "X-Product-Code"
|
|
@@ -14,8 +14,8 @@ DEFAULT_TTL = 3600
|
|
|
14
14
|
class OAuthClient:
|
|
15
15
|
def __init__(
|
|
16
16
|
self,
|
|
17
|
-
base_url: str,
|
|
18
17
|
product_code: str,
|
|
18
|
+
base_url: Optional[str] = None,
|
|
19
19
|
redirect_url: Optional[str] = None,
|
|
20
20
|
single_session: bool = False,
|
|
21
21
|
cache: Optional[BaseCache] = None,
|
|
@@ -28,6 +28,8 @@ class OAuthClient:
|
|
|
28
28
|
:param redirect_url: 可选,重定向地址
|
|
29
29
|
:param single_session: 是否单会话登录
|
|
30
30
|
"""
|
|
31
|
+
if not base_url:
|
|
32
|
+
base_url = "http://172.27.92.74"
|
|
31
33
|
self._base_url = base_url.rstrip("/")
|
|
32
34
|
self._product_code = product_code
|
|
33
35
|
self._redirect_url = redirect_url
|
|
@@ -43,7 +45,13 @@ class OAuthClient:
|
|
|
43
45
|
return await asyncio.to_thread(request, *args, **kwargs)
|
|
44
46
|
|
|
45
47
|
def _headers(self, extra: Optional[Dict[str, str]] = None) -> Dict[str, str]:
|
|
46
|
-
headers = {
|
|
48
|
+
headers = {
|
|
49
|
+
PRODUCT_HEADER: self._product_code,
|
|
50
|
+
}
|
|
51
|
+
if self._base_url == 'http://172.27.92.74':
|
|
52
|
+
headers.update({
|
|
53
|
+
"Host": "auth.nc.com"
|
|
54
|
+
})
|
|
47
55
|
if extra:
|
|
48
56
|
headers.update(extra)
|
|
49
57
|
return headers
|
|
@@ -214,19 +222,23 @@ class OAuthClient:
|
|
|
214
222
|
return UserResponse(res_dict)
|
|
215
223
|
|
|
216
224
|
async def say_my_name_async(self, token: str) -> UserResponse:
|
|
217
|
-
if not self._async_cache:
|
|
218
|
-
raise RuntimeError("异步方法只支持异步缓存,请传入 async_cache")
|
|
219
|
-
|
|
220
225
|
"""异步获取当前用户"""
|
|
221
226
|
key = f"user:{token}"
|
|
222
|
-
|
|
227
|
+
if self._async_cache:
|
|
228
|
+
data = await self._cache.get(key)
|
|
229
|
+
else:
|
|
230
|
+
data = self._cache.get(key)
|
|
231
|
+
|
|
223
232
|
if data:
|
|
224
233
|
return UserResponse(data)
|
|
225
234
|
|
|
226
235
|
headers = self._headers({"Authorization": f"Bearer {token}"})
|
|
227
236
|
res_dict = await self._arequest("GET", f"{self._base_url}/api/me", headers=headers)
|
|
228
237
|
if res_dict.get("success", True):
|
|
229
|
-
|
|
238
|
+
if self._async_cache:
|
|
239
|
+
await self._cache_user_async(token, res_dict)
|
|
240
|
+
else:
|
|
241
|
+
self._cache_user(token, res_dict)
|
|
230
242
|
|
|
231
243
|
return UserResponse(res_dict)
|
|
232
244
|
|
|
@@ -262,10 +274,125 @@ class OAuthClient:
|
|
|
262
274
|
headers = self._headers({"Authorization": f"Bearer {token}"})
|
|
263
275
|
resp = await self._arequest("POST", f"{self._base_url}/api/auth/logout", headers=headers)
|
|
264
276
|
|
|
265
|
-
|
|
266
|
-
|
|
277
|
+
if self._async_cache:
|
|
278
|
+
data = await self._cache.get(f"user:{token}")
|
|
279
|
+
await self._uncache_user_async(token, data)
|
|
280
|
+
else:
|
|
281
|
+
data = self._cache.get(f"user:{token}")
|
|
282
|
+
self._uncache_user(token, data)
|
|
267
283
|
return resp
|
|
268
284
|
|
|
285
|
+
# 密码学登录
|
|
286
|
+
def open_sesame(self, user_name:str, password: str) -> CallbackResponse:
|
|
287
|
+
params = {"single_session": str(self._single_session).lower()}
|
|
288
|
+
|
|
289
|
+
form = {
|
|
290
|
+
"username": user_name,
|
|
291
|
+
"password": password,
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
res_dict = request("POST", f"{self._base_url}/api/auth/login", headers=self._headers(), params=params, form_body=form)
|
|
295
|
+
|
|
296
|
+
return CallbackResponse(res_dict)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
async def open_sesame_async(self, user_name:str, password: str) -> CallbackResponse:
|
|
300
|
+
params = {"single_session": str(self._single_session).lower()}
|
|
301
|
+
|
|
302
|
+
form = {
|
|
303
|
+
"username": user_name,
|
|
304
|
+
"password": password,
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
res_dict = await self._arequest(
|
|
308
|
+
"POST",
|
|
309
|
+
f"{self._base_url}/api/auth/login",
|
|
310
|
+
params=params,
|
|
311
|
+
form_body=form,
|
|
312
|
+
headers={
|
|
313
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
314
|
+
**self._headers(),
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
return CallbackResponse(res_dict)
|
|
318
|
+
|
|
319
|
+
def forget_me_not(self, user_email: str, redirect_url: str):
|
|
320
|
+
"""
|
|
321
|
+
忘记密码
|
|
322
|
+
:param user_email:
|
|
323
|
+
:param redirect_url:
|
|
324
|
+
:return:
|
|
325
|
+
"""
|
|
326
|
+
headers = self._headers()
|
|
327
|
+
json_data = {
|
|
328
|
+
"email": user_email,
|
|
329
|
+
"redirect_url": redirect_url
|
|
330
|
+
}
|
|
331
|
+
return request("POST", f"{self._base_url}/api/auth/forgot-password", headers=headers, json_body=json_data)
|
|
332
|
+
|
|
333
|
+
def lily_of_the_valley(self, password_token: str, password: str):
|
|
334
|
+
"""
|
|
335
|
+
找回密码
|
|
336
|
+
:param password_token: forgot_password获取的验证token
|
|
337
|
+
:param password: 新密码
|
|
338
|
+
:return:
|
|
339
|
+
"""
|
|
340
|
+
json_data = {
|
|
341
|
+
"token": password_token,
|
|
342
|
+
"password": password
|
|
343
|
+
}
|
|
344
|
+
return request("POST", f"{self._base_url}/api/auth/reset-password", headers=self._headers(), json_body=json_data)
|
|
345
|
+
|
|
346
|
+
def register_apply(self, ip_address: str, email: str, password: str, full_name: str = None, redirect_url: str = None) -> dict:
|
|
347
|
+
"""
|
|
348
|
+
邮件注册申请
|
|
349
|
+
:param ip_address:
|
|
350
|
+
:param redirect_url: 不填默认为系统配置的回调地址
|
|
351
|
+
:param password: 用户的密码
|
|
352
|
+
:param full_name: 用户的名称
|
|
353
|
+
:param email: 用户的邮箱
|
|
354
|
+
:return:
|
|
355
|
+
"""
|
|
356
|
+
json_data = {
|
|
357
|
+
"email": email,
|
|
358
|
+
"password": password,
|
|
359
|
+
"full_name": full_name,
|
|
360
|
+
}
|
|
361
|
+
params = {"redirect_url": redirect_url, "ip_address": ip_address}
|
|
362
|
+
return request("POST", f"{self._base_url}/api/auth/register-apply", params=params, headers=self._headers(),
|
|
363
|
+
json_body=json_data)
|
|
364
|
+
|
|
365
|
+
def register(self, register_token: str, full_name: str = None) -> dict:
|
|
366
|
+
"""
|
|
367
|
+
邮箱注册
|
|
368
|
+
:param register_token:
|
|
369
|
+
:param full_name: 可不填, 填写后会修改名称
|
|
370
|
+
:return:
|
|
371
|
+
"""
|
|
372
|
+
json_data = {
|
|
373
|
+
"token": register_token,
|
|
374
|
+
"full_name": full_name,
|
|
375
|
+
}
|
|
376
|
+
return request("POST", f"{self._base_url}/api/auth/register", headers=self._headers(),
|
|
377
|
+
json_body=json_data)
|
|
378
|
+
|
|
379
|
+
def lycoris(self, token: str, password: str):
|
|
380
|
+
"""
|
|
381
|
+
账户注销
|
|
382
|
+
:param password: 用户密码 用来确认用户是否正确
|
|
383
|
+
:param token: 用户token
|
|
384
|
+
:return:
|
|
385
|
+
"""
|
|
386
|
+
user = self.say_my_name(token=token)
|
|
387
|
+
user_id = user.user_id
|
|
388
|
+
|
|
389
|
+
headers = self._headers({"Authorization": f"Bearer {token}"})
|
|
390
|
+
form_data = {
|
|
391
|
+
"username": user.email,
|
|
392
|
+
"password": password
|
|
393
|
+
}
|
|
394
|
+
return request("POST", f"{self._base_url}/api/users/{ user_id }/remove", headers=headers, form_body=form_data)
|
|
395
|
+
|
|
269
396
|
async def main():
|
|
270
397
|
def get_redis_url() -> str:
|
|
271
398
|
return f'redis://default:1q2w3e@localhost:6379/1'
|
|
@@ -276,18 +403,19 @@ async def main():
|
|
|
276
403
|
_redis = redis.from_url(get_redis_url(), decode_responses=True)
|
|
277
404
|
|
|
278
405
|
redis_cache = AsyncRedisCache(_redis)
|
|
406
|
+
import socket
|
|
407
|
+
print(socket.gethostbyname("dev.ncuser.com"))
|
|
408
|
+
|
|
409
|
+
client = OAuthClient("kode", "http://dev.ncuser.com", "http://localhost:8000/auth/google/custom_callback", single_session=True, cache=redis_cache)
|
|
410
|
+
authorize = await client.say_my_name_async("QtbMAqXNwrsy-7dr-D_lIVvUu88gjhPM0fBXeJTaOiA")
|
|
279
411
|
|
|
280
|
-
client
|
|
281
|
-
#
|
|
282
|
-
# print(authorize)
|
|
412
|
+
client.open_sesame_async("glztestvt1@zingfront.com", "123456789")
|
|
413
|
+
# res = client.forgot_password("QtbMAqXNwrsy-7dr-D_lIVvUu88gjhPM0fBXeJTaOiA")
|
|
283
414
|
|
|
415
|
+
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1IiwicGFzc3dvcmRfZmdwdCI6IiRhcmdvbjJpZCR2PTE5JG09NjU1MzYsdD0zLHA9NCRYUlQ1K1p3Uk5sbjhKQzQrZW94TFlnJERadnFKb29xUDNMUGVJbEV6OVR5TjZIdm1LYW9yYnpvdGxGRlB5SlBKZE0iLCJhdWQiOiJmYXN0YXBpLXVzZXJzOnJlc2V0IiwiZXhwIjoxNzYxNTU4MTUxfQ.rSr8tRql4ZsE2k-WGHzhq9aT387E9jXGJ_bNomC4LKA"
|
|
416
|
+
print(client.logout_async(token, "965965965"))
|
|
417
|
+
print(authorize)
|
|
284
418
|
|
|
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
419
|
|
|
292
420
|
|
|
293
421
|
if __name__ == '__main__':
|
nc_user_manager/models.py
CHANGED
|
@@ -15,8 +15,8 @@ class UserResponse(dict):
|
|
|
15
15
|
return self.get("email")
|
|
16
16
|
|
|
17
17
|
@property
|
|
18
|
-
def
|
|
19
|
-
return self.get("
|
|
18
|
+
def avatar(self) -> Optional[str]:
|
|
19
|
+
return self.get("avatar")
|
|
20
20
|
|
|
21
21
|
@property
|
|
22
22
|
def full_name(self) -> Optional[str]:
|
|
@@ -26,6 +26,10 @@ class UserResponse(dict):
|
|
|
26
26
|
def role(self) -> Optional[str]:
|
|
27
27
|
return self.get("role")
|
|
28
28
|
|
|
29
|
+
@property
|
|
30
|
+
def user_id(self) -> Optional[str]:
|
|
31
|
+
return self.get("user_id")
|
|
32
|
+
|
|
29
33
|
class CallbackResponse(dict):
|
|
30
34
|
@property
|
|
31
35
|
def token(self) -> str:
|
|
@@ -44,5 +48,5 @@ class CallbackResponse(dict):
|
|
|
44
48
|
return self.get("email")
|
|
45
49
|
|
|
46
50
|
@property
|
|
47
|
-
def
|
|
48
|
-
return self.get("
|
|
51
|
+
def avatar(self) -> str:
|
|
52
|
+
return self.get("avatar")
|
nc_user_manager/utils.py
CHANGED
|
@@ -10,7 +10,8 @@ def request(
|
|
|
10
10
|
url: str,
|
|
11
11
|
params: Optional[Dict[str, Any]] = None,
|
|
12
12
|
headers: Optional[Dict[str, str]] = None,
|
|
13
|
-
json_body: Optional[dict] = None
|
|
13
|
+
json_body: Optional[dict] = None,
|
|
14
|
+
form_body: Optional[dict] = None,
|
|
14
15
|
) -> dict:
|
|
15
16
|
"""
|
|
16
17
|
发送 HTTP 请求并返回统一结果,不抛异常
|
|
@@ -28,12 +29,20 @@ def request(
|
|
|
28
29
|
url = f"{url}?{query}"
|
|
29
30
|
|
|
30
31
|
data = None
|
|
32
|
+
|
|
33
|
+
# JSON 请求
|
|
31
34
|
if json_body is not None:
|
|
32
35
|
data = json.dumps(json_body).encode("utf-8")
|
|
33
36
|
if headers is None:
|
|
34
37
|
headers = {}
|
|
35
38
|
headers["Content-Type"] = "application/json"
|
|
36
39
|
|
|
40
|
+
# Form 表单请求
|
|
41
|
+
if form_body is not None:
|
|
42
|
+
data = urllib.parse.urlencode(form_body).encode("utf-8")
|
|
43
|
+
headers = headers or {}
|
|
44
|
+
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
|
45
|
+
|
|
37
46
|
req = urllib.request.Request(url, method=method.upper(), data=data)
|
|
38
47
|
if headers:
|
|
39
48
|
for k, v in headers.items():
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nc-user-terminator
|
|
3
|
+
Version: 0.1.17
|
|
4
|
+
Summary: OAuth client wrapper for multi-tenant projects
|
|
5
|
+
Author: bw_song
|
|
6
|
+
Author-email: m132777096902@gmail.com
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Requires-Dist: cachetools==6.2.0
|
|
10
|
+
Dynamic: author-email
|
|
11
|
+
Dynamic: requires-python
|
|
12
|
+
|
|
13
|
+
# 更新
|
|
14
|
+
+ V0.1.5
|
|
15
|
+
- 新增本地缓存机制
|
|
16
|
+
+ v0.1.6
|
|
17
|
+
- 默认连接地址
|
|
18
|
+
+ v0.1.7
|
|
19
|
+
- 映射host
|
|
20
|
+
+ v0.1.8
|
|
21
|
+
- 调整相对路径
|
|
22
|
+
+ v0.1.9
|
|
23
|
+
- 修改缓存配置
|
|
24
|
+
+ v0.1.10
|
|
25
|
+
- 获取用户信息,本地缓存配置
|
|
26
|
+
+ v0.1.11
|
|
27
|
+
- 用户头像字段调整
|
|
28
|
+
+ v0.1.12
|
|
29
|
+
- 新增密码学登录
|
|
30
|
+
- 新增修改密码
|
|
31
|
+
- 支持重置社媒账号密码
|
|
32
|
+
+ v0.1.13
|
|
33
|
+
- 包路径调整
|
|
34
|
+
+ v0.1.14
|
|
35
|
+
- 新增facebook第三方登录
|
|
36
|
+
- 新增邮箱注册功能
|
|
37
|
+
+ v0.1.15
|
|
38
|
+
- 新增忘记密码
|
|
39
|
+
- 新增找回密码
|
|
40
|
+
- 新增账户注销
|
|
41
|
+
+ v0.1.16
|
|
42
|
+
- 修改接口返回数据
|
|
43
|
+
+ v0.1.17
|
|
44
|
+
- 用户注销调整
|
|
@@ -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=r8M-HXaku8D_x4zp4fxVY5avjjr3TKqmHd6ILQXl-cc,16055
|
|
4
|
+
nc_user_manager/exceptions.py,sha256=yUMDrh1HHZF36UUadQNHvJlDgEYSYoYOObs8Q11fjrE,351
|
|
5
|
+
nc_user_manager/models.py,sha256=WgNC7z7Xy9fok5tA6CawxvBmEhGM6J0KCD3bk2MMUWU,1166
|
|
6
|
+
nc_user_manager/utils.py,sha256=zn0ds3UftTaEnrTVDn0YL9N-EkVWpbJtowFzAotU80E,2608
|
|
7
|
+
nc_user_terminator-0.1.17.dist-info/METADATA,sha256=pfxhwK_sbiC6quB-jO8u-_XwfYsvsN1VajsGkG9Lze8,967
|
|
8
|
+
nc_user_terminator-0.1.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
9
|
+
nc_user_terminator-0.1.17.dist-info/top_level.txt,sha256=kOAUtl6RYo-x3vMJL8It3KCJLoIFPvMUiAAyXjPQTYA,16
|
|
10
|
+
nc_user_terminator-0.1.17.dist-info/RECORD,,
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: nc-user-terminator
|
|
3
|
-
Version: 0.1.5
|
|
4
|
-
Summary: OAuth client wrapper for multi-tenant projects
|
|
5
|
-
Author: bw_song
|
|
6
|
-
Author-email: m132777096902@gmail.com
|
|
7
|
-
Requires-Python: >=3.8
|
|
8
|
-
Description-Content-Type: text/markdown
|
|
9
|
-
Requires-Dist: cachetools==6.2.0
|
|
10
|
-
Dynamic: author-email
|
|
11
|
-
Dynamic: requires-python
|
|
12
|
-
|
|
13
|
-
# 更新
|
|
14
|
-
+ V0.1.5
|
|
15
|
-
- 新增本地缓存机制
|
|
@@ -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=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,,
|
|
File without changes
|
|
File without changes
|