micosauth 0.1.0__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.
- micosauth-0.1.0/MANIFEST.in +1 -0
- micosauth-0.1.0/PKG-INFO +353 -0
- micosauth-0.1.0/README.md +319 -0
- micosauth-0.1.0/docs/PUBLISH.md +44 -0
- micosauth-0.1.0/docs/PYPI_RELEASE.md +29 -0
- micosauth-0.1.0/pyproject.toml +79 -0
- micosauth-0.1.0/setup.cfg +4 -0
- micosauth-0.1.0/tests/test_auth_modes.py +117 -0
- micosauth-0.1.0/tests/test_fastapi.py +51 -0
- micosauth-0.1.0/tests/test_fastapi_e2e.py +139 -0
- micosauth-0.1.0/tests/test_fastapi_multi_realm.py +217 -0
- micosauth-0.1.0/tests/test_provider.py +60 -0
- micosauth-0.1.0/tests/test_redis_integration.py +205 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
recursive-include docs *.md
|
micosauth-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: micosauth
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Redis-based auth and session package for Python applications
|
|
5
|
+
Author-email: CharlieZhang <charlie@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jiangbyte/micosauth
|
|
8
|
+
Project-URL: Documentation, https://github.com/jiangbyte/micosauth
|
|
9
|
+
Project-URL: Repository, https://github.com/jiangbyte/micosauth
|
|
10
|
+
Project-URL: Issues, https://github.com/jiangbyte/micosauth/issues
|
|
11
|
+
Keywords: auth,authentication,authorization,redis,fastapi,session,token
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Framework :: FastAPI
|
|
21
|
+
Classifier: Topic :: Security
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
Requires-Dist: fastapi>=0.136.1
|
|
26
|
+
Requires-Dist: redis>=7.4.0
|
|
27
|
+
Provides-Extra: fastapi
|
|
28
|
+
Requires-Dist: fastapi>=0.136.1; extra == "fastapi"
|
|
29
|
+
Requires-Dist: starlette>=0.37.2; extra == "fastapi"
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-asyncio>=0.25.0; extra == "dev"
|
|
33
|
+
Requires-Dist: httpx>=0.28.0; extra == "dev"
|
|
34
|
+
|
|
35
|
+
# micosauth 使用文档
|
|
36
|
+
|
|
37
|
+
`micosauth` 是一个基于 Redis 的通用认证鉴权包,当前版本核心模型是:
|
|
38
|
+
|
|
39
|
+
- 多 realm
|
|
40
|
+
- 基于 `login_id` 登录
|
|
41
|
+
- 默认 64 位字符串 token
|
|
42
|
+
- 支持多设备、多 token 策略控制
|
|
43
|
+
- 普通 token 与临时 token
|
|
44
|
+
- `MicosAuthUtil` 负责认证、鉴权、撤销、反查
|
|
45
|
+
- `MicosSessionUtil` 负责查询、统计、分布分析
|
|
46
|
+
|
|
47
|
+
## 1. 核心对象
|
|
48
|
+
|
|
49
|
+
- `MicosSetting`
|
|
50
|
+
启动配置对象
|
|
51
|
+
- `MicosService`
|
|
52
|
+
启动装配对象
|
|
53
|
+
- `MicosAuthUtil`
|
|
54
|
+
主认证鉴权工具
|
|
55
|
+
- `MicosSessionUtil`
|
|
56
|
+
会话查询统计工具
|
|
57
|
+
- `MicosTokenUtil`
|
|
58
|
+
token 生成工具
|
|
59
|
+
|
|
60
|
+
## 2. 安装
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install micosauth
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
如需 FastAPI 适配层:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install "micosauth[fastapi]"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 3. 启动接入
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from micosauth import (
|
|
76
|
+
MicosAuthUtil,
|
|
77
|
+
MicosRealmSetting,
|
|
78
|
+
MicosRedisSetting,
|
|
79
|
+
MicosService,
|
|
80
|
+
MicosSessionUtil,
|
|
81
|
+
MicosSetting,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
micos_setting = MicosSetting(
|
|
85
|
+
redis=MicosRedisSetting(url="redis://:123456@127.0.0.1:6379/1"),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
micos_service = MicosService(micos_setting)
|
|
89
|
+
micos_service.register_realm(MicosRealmSetting(realm_id="admin"))
|
|
90
|
+
micos_service.register_realm(MicosRealmSetting(realm_id="user"))
|
|
91
|
+
|
|
92
|
+
await micos_service.init()
|
|
93
|
+
|
|
94
|
+
micos_auth = MicosAuthUtil(micos_service)
|
|
95
|
+
micos_session = MicosSessionUtil(micos_service)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 4. Realm 配置
|
|
99
|
+
|
|
100
|
+
`MicosRealmSetting` 当前支持的核心策略项:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
MicosRealmSetting(
|
|
104
|
+
realm_id="admin",
|
|
105
|
+
token_name="Authorization",
|
|
106
|
+
token_ttl_seconds=2592000,
|
|
107
|
+
temp_token_ttl_seconds=300,
|
|
108
|
+
allow_multi_device_login=True,
|
|
109
|
+
keep_old_token_on_same_device_login=False,
|
|
110
|
+
keep_old_token_on_new_device_login=True,
|
|
111
|
+
max_devices_per_login_id=2,
|
|
112
|
+
max_tokens_per_login_id=5,
|
|
113
|
+
max_tokens_per_device=1,
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
字段含义:
|
|
118
|
+
|
|
119
|
+
- `allow_multi_device_login`
|
|
120
|
+
是否允许多设备同时登录
|
|
121
|
+
- `keep_old_token_on_same_device_login`
|
|
122
|
+
同设备再次登录时是否保留旧 token
|
|
123
|
+
- `keep_old_token_on_new_device_login`
|
|
124
|
+
新设备登录时是否保留其他设备旧 token
|
|
125
|
+
- `max_devices_per_login_id`
|
|
126
|
+
每个 `login_id` 允许的最大设备数,`0` 表示不限制
|
|
127
|
+
- `max_tokens_per_login_id`
|
|
128
|
+
每个 `login_id` 允许的最大 token 数,`0` 表示不限制
|
|
129
|
+
- `max_tokens_per_device`
|
|
130
|
+
每个设备允许的最大 token 数,`0` 表示不限制
|
|
131
|
+
|
|
132
|
+
## 5. 注册 AccessProvider
|
|
133
|
+
|
|
134
|
+
使用方需要自己实现权限、角色、数据范围获取逻辑。
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from micosauth import MicosAccessProvider
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class AdminAccessProvider:
|
|
141
|
+
async def get_roles(self, realm_id: str, login_id: str) -> list[str]:
|
|
142
|
+
return ["ADMIN"]
|
|
143
|
+
|
|
144
|
+
async def get_permissions(self, realm_id: str, login_id: str) -> list[str]:
|
|
145
|
+
return ["sys:user:view", "sys:session:page"]
|
|
146
|
+
|
|
147
|
+
async def get_data_scopes(self, realm_id: str, login_id: str) -> list[str]:
|
|
148
|
+
return ["ALL"]
|
|
149
|
+
|
|
150
|
+
async def get_extra(self, realm_id: str, login_id: str) -> dict:
|
|
151
|
+
return {"nickname": "管理员"}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
注册方式:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
micos_service.register_access_provider("admin", AdminAccessProvider())
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## 6. 登录与普通 token
|
|
161
|
+
|
|
162
|
+
登录只需要 `login_id`,推荐同时传入 `device_id`:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
result = await micos_auth.login(
|
|
166
|
+
"admin",
|
|
167
|
+
"1001",
|
|
168
|
+
device_id="pc",
|
|
169
|
+
extra={"nickname": "管理员"},
|
|
170
|
+
)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
返回示例:
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
{
|
|
177
|
+
"token": "...64位字符串...",
|
|
178
|
+
"login_id": "1001",
|
|
179
|
+
"realm_id": "admin",
|
|
180
|
+
"device_id": "pc",
|
|
181
|
+
"expires_at": "2026-06-14T12:00:00+00:00",
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
说明:
|
|
186
|
+
|
|
187
|
+
- 当前模型中不再暴露独立 `session_id`
|
|
188
|
+
- 会话主体围绕 `realm_id + login_id` 组织
|
|
189
|
+
- token 是登录明细单元
|
|
190
|
+
|
|
191
|
+
## 7. 鉴权与反查
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
is_valid = await micos_auth.is_token_valid(token, "admin")
|
|
195
|
+
inspect_result = await micos_auth.inspect_token(token, "admin")
|
|
196
|
+
login_id = await micos_auth.get_login_id_by_token(token, "admin")
|
|
197
|
+
roles = await micos_auth.get_roles("admin", "1001")
|
|
198
|
+
permissions = await micos_auth.get_permissions("admin", "1001")
|
|
199
|
+
data_scopes = await micos_auth.get_data_scopes_by_login_id("admin", "1001")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 8. 临时 token
|
|
203
|
+
|
|
204
|
+
创建:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
temp = await micos_auth.create_temp_token(
|
|
208
|
+
"admin",
|
|
209
|
+
temp_id="file-1001",
|
|
210
|
+
type="download",
|
|
211
|
+
time=300,
|
|
212
|
+
extra={"filename": "report.xlsx"},
|
|
213
|
+
)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
校验:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
ok = await micos_auth.verify_temp_token(
|
|
220
|
+
temp["token"],
|
|
221
|
+
"admin",
|
|
222
|
+
type="download",
|
|
223
|
+
)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## 9. 会话查询与统计
|
|
227
|
+
|
|
228
|
+
当前查询模型:
|
|
229
|
+
|
|
230
|
+
- `session` 是 `login_id` 级聚合
|
|
231
|
+
- `token` 是具体登录明细
|
|
232
|
+
- `device` 是 token 分组维度
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
sessions = await micos_session.list_sessions("admin")
|
|
236
|
+
page = await micos_session.page_sessions("admin", current=1, size=20)
|
|
237
|
+
login_session = await micos_session.get_session("admin", "1001")
|
|
238
|
+
tokens = await micos_session.list_tokens("admin", "1001")
|
|
239
|
+
device_tokens = await micos_session.list_device_sessions("admin", "1001", "pc")
|
|
240
|
+
device_summaries = await micos_session.list_device_summaries("admin", "1001")
|
|
241
|
+
|
|
242
|
+
online_count = await micos_session.count_online_sessions("admin")
|
|
243
|
+
login_token_count = await micos_session.count_login_id_sessions("admin", "1001")
|
|
244
|
+
device_token_count = await micos_session.count_device_tokens("admin", "1001", "pc")
|
|
245
|
+
|
|
246
|
+
analysis = await micos_session.get_analysis()
|
|
247
|
+
chart = await micos_session.get_chart_data(days=7)
|
|
248
|
+
distribution = await micos_session.get_realm_distribution()
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
统计对象说明:
|
|
252
|
+
|
|
253
|
+
- `get_analysis()`
|
|
254
|
+
返回总登录数、总 token 数、总设备数、最近一小时新增 token 数
|
|
255
|
+
- `get_chart_data(days=7)`
|
|
256
|
+
返回按天统计的 token 创建趋势
|
|
257
|
+
- `get_realm_distribution()`
|
|
258
|
+
返回各 realm 的登录数、token 数、设备数分布
|
|
259
|
+
- `list_device_summaries("admin", "1001")`
|
|
260
|
+
直接返回某个 `login_id` 下各设备摘要,包括 token 数、最近登录时间、最近访问时间
|
|
261
|
+
|
|
262
|
+
## 10. 撤销与下线
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
await micos_auth.revoke_token("admin", token)
|
|
266
|
+
await micos_auth.revoke_login("admin", "1001")
|
|
267
|
+
await micos_auth.kickout_login_id("admin", "1001")
|
|
268
|
+
await micos_auth.kickout_device("admin", "1001", "pc")
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
兼容接口:
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
await micos_auth.logout_current("admin", token)
|
|
275
|
+
await micos_auth.logout_login_id("admin", "1001")
|
|
276
|
+
await micos_auth.logout_device("admin", "1001", "pc")
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## 11. Redis 存储模型
|
|
280
|
+
|
|
281
|
+
当前 Redis 主结构围绕 `realm_id + login_id`:
|
|
282
|
+
|
|
283
|
+
- `micosauth:{realm_id}:{login_id}:session`
|
|
284
|
+
登录主体聚合数据
|
|
285
|
+
- `micosauth:{realm_id}:{login_id}:tokens`
|
|
286
|
+
token 明细 `HASH`
|
|
287
|
+
- `micosauth:{realm_id}:{login_id}:device_tokens:{device_id}`
|
|
288
|
+
设备维度 token 明细 `HASH`
|
|
289
|
+
- `micosauth:{realm_id}:token_lookup:{token}`
|
|
290
|
+
token 反查 `login_id`
|
|
291
|
+
- `micosauth:{realm_id}:login_index`
|
|
292
|
+
realm 级 login 分布索引
|
|
293
|
+
- `micosauth:{realm_id}:token_index`
|
|
294
|
+
token 过期索引
|
|
295
|
+
- `micosauth:{realm_id}:created_index`
|
|
296
|
+
token 创建时间索引
|
|
297
|
+
- `micosauth:{realm_id}:temp:{token}`
|
|
298
|
+
临时 token
|
|
299
|
+
|
|
300
|
+
## 12. FastAPI 接入
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
from fastapi import FastAPI
|
|
304
|
+
from micosauth.adapters.fastapi import build_micosauth_lifespan, install_fastapi_auth
|
|
305
|
+
|
|
306
|
+
app = FastAPI(lifespan=build_micosauth_lifespan(micos_service))
|
|
307
|
+
install_fastapi_auth(app, micos_service)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
说明:
|
|
311
|
+
|
|
312
|
+
- FastAPI dependency 必须显式传 `realm`
|
|
313
|
+
- decorator 必须显式传 `realm`
|
|
314
|
+
- middleware 不做默认自动认证
|
|
315
|
+
- `micosauth` 不负责猜测 realm
|
|
316
|
+
|
|
317
|
+
示例:
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
from fastapi import Depends
|
|
321
|
+
from micosauth.adapters.fastapi import require_login_dep
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
@app.get("/admin/me", dependencies=[Depends(require_login_dep(realm="admin"))])
|
|
325
|
+
async def admin_me():
|
|
326
|
+
return {"ok": True}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## 13. OR / AND 鉴权模式
|
|
330
|
+
|
|
331
|
+
角色和权限校验都支持:
|
|
332
|
+
|
|
333
|
+
- `AND`
|
|
334
|
+
- `OR`
|
|
335
|
+
- 权限支持通配符匹配
|
|
336
|
+
|
|
337
|
+
```python
|
|
338
|
+
await micos_auth.require_roles(token, ["ADMIN", "AUDITOR"], "admin", mode="AND")
|
|
339
|
+
await micos_auth.require_permissions(token, ["sys:user:*", "sys:log:view"], "admin", mode="OR")
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## 14. 当前状态
|
|
343
|
+
|
|
344
|
+
当前版本已经完成:
|
|
345
|
+
|
|
346
|
+
- Redis 真测
|
|
347
|
+
- FastAPI 集成真测
|
|
348
|
+
- 多 realm 接入真测
|
|
349
|
+
- 多设备、多 token 策略真测
|
|
350
|
+
- 设备摘要查询真测
|
|
351
|
+
- 角色、权限 `AND/OR` 模式测试
|
|
352
|
+
- 权限通配符测试
|
|
353
|
+
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# micosauth 使用文档
|
|
2
|
+
|
|
3
|
+
`micosauth` 是一个基于 Redis 的通用认证鉴权包,当前版本核心模型是:
|
|
4
|
+
|
|
5
|
+
- 多 realm
|
|
6
|
+
- 基于 `login_id` 登录
|
|
7
|
+
- 默认 64 位字符串 token
|
|
8
|
+
- 支持多设备、多 token 策略控制
|
|
9
|
+
- 普通 token 与临时 token
|
|
10
|
+
- `MicosAuthUtil` 负责认证、鉴权、撤销、反查
|
|
11
|
+
- `MicosSessionUtil` 负责查询、统计、分布分析
|
|
12
|
+
|
|
13
|
+
## 1. 核心对象
|
|
14
|
+
|
|
15
|
+
- `MicosSetting`
|
|
16
|
+
启动配置对象
|
|
17
|
+
- `MicosService`
|
|
18
|
+
启动装配对象
|
|
19
|
+
- `MicosAuthUtil`
|
|
20
|
+
主认证鉴权工具
|
|
21
|
+
- `MicosSessionUtil`
|
|
22
|
+
会话查询统计工具
|
|
23
|
+
- `MicosTokenUtil`
|
|
24
|
+
token 生成工具
|
|
25
|
+
|
|
26
|
+
## 2. 安装
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install micosauth
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
如需 FastAPI 适配层:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install "micosauth[fastapi]"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 3. 启动接入
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from micosauth import (
|
|
42
|
+
MicosAuthUtil,
|
|
43
|
+
MicosRealmSetting,
|
|
44
|
+
MicosRedisSetting,
|
|
45
|
+
MicosService,
|
|
46
|
+
MicosSessionUtil,
|
|
47
|
+
MicosSetting,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
micos_setting = MicosSetting(
|
|
51
|
+
redis=MicosRedisSetting(url="redis://:123456@127.0.0.1:6379/1"),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
micos_service = MicosService(micos_setting)
|
|
55
|
+
micos_service.register_realm(MicosRealmSetting(realm_id="admin"))
|
|
56
|
+
micos_service.register_realm(MicosRealmSetting(realm_id="user"))
|
|
57
|
+
|
|
58
|
+
await micos_service.init()
|
|
59
|
+
|
|
60
|
+
micos_auth = MicosAuthUtil(micos_service)
|
|
61
|
+
micos_session = MicosSessionUtil(micos_service)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 4. Realm 配置
|
|
65
|
+
|
|
66
|
+
`MicosRealmSetting` 当前支持的核心策略项:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
MicosRealmSetting(
|
|
70
|
+
realm_id="admin",
|
|
71
|
+
token_name="Authorization",
|
|
72
|
+
token_ttl_seconds=2592000,
|
|
73
|
+
temp_token_ttl_seconds=300,
|
|
74
|
+
allow_multi_device_login=True,
|
|
75
|
+
keep_old_token_on_same_device_login=False,
|
|
76
|
+
keep_old_token_on_new_device_login=True,
|
|
77
|
+
max_devices_per_login_id=2,
|
|
78
|
+
max_tokens_per_login_id=5,
|
|
79
|
+
max_tokens_per_device=1,
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
字段含义:
|
|
84
|
+
|
|
85
|
+
- `allow_multi_device_login`
|
|
86
|
+
是否允许多设备同时登录
|
|
87
|
+
- `keep_old_token_on_same_device_login`
|
|
88
|
+
同设备再次登录时是否保留旧 token
|
|
89
|
+
- `keep_old_token_on_new_device_login`
|
|
90
|
+
新设备登录时是否保留其他设备旧 token
|
|
91
|
+
- `max_devices_per_login_id`
|
|
92
|
+
每个 `login_id` 允许的最大设备数,`0` 表示不限制
|
|
93
|
+
- `max_tokens_per_login_id`
|
|
94
|
+
每个 `login_id` 允许的最大 token 数,`0` 表示不限制
|
|
95
|
+
- `max_tokens_per_device`
|
|
96
|
+
每个设备允许的最大 token 数,`0` 表示不限制
|
|
97
|
+
|
|
98
|
+
## 5. 注册 AccessProvider
|
|
99
|
+
|
|
100
|
+
使用方需要自己实现权限、角色、数据范围获取逻辑。
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from micosauth import MicosAccessProvider
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class AdminAccessProvider:
|
|
107
|
+
async def get_roles(self, realm_id: str, login_id: str) -> list[str]:
|
|
108
|
+
return ["ADMIN"]
|
|
109
|
+
|
|
110
|
+
async def get_permissions(self, realm_id: str, login_id: str) -> list[str]:
|
|
111
|
+
return ["sys:user:view", "sys:session:page"]
|
|
112
|
+
|
|
113
|
+
async def get_data_scopes(self, realm_id: str, login_id: str) -> list[str]:
|
|
114
|
+
return ["ALL"]
|
|
115
|
+
|
|
116
|
+
async def get_extra(self, realm_id: str, login_id: str) -> dict:
|
|
117
|
+
return {"nickname": "管理员"}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
注册方式:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
micos_service.register_access_provider("admin", AdminAccessProvider())
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 6. 登录与普通 token
|
|
127
|
+
|
|
128
|
+
登录只需要 `login_id`,推荐同时传入 `device_id`:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
result = await micos_auth.login(
|
|
132
|
+
"admin",
|
|
133
|
+
"1001",
|
|
134
|
+
device_id="pc",
|
|
135
|
+
extra={"nickname": "管理员"},
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
返回示例:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
{
|
|
143
|
+
"token": "...64位字符串...",
|
|
144
|
+
"login_id": "1001",
|
|
145
|
+
"realm_id": "admin",
|
|
146
|
+
"device_id": "pc",
|
|
147
|
+
"expires_at": "2026-06-14T12:00:00+00:00",
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
说明:
|
|
152
|
+
|
|
153
|
+
- 当前模型中不再暴露独立 `session_id`
|
|
154
|
+
- 会话主体围绕 `realm_id + login_id` 组织
|
|
155
|
+
- token 是登录明细单元
|
|
156
|
+
|
|
157
|
+
## 7. 鉴权与反查
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
is_valid = await micos_auth.is_token_valid(token, "admin")
|
|
161
|
+
inspect_result = await micos_auth.inspect_token(token, "admin")
|
|
162
|
+
login_id = await micos_auth.get_login_id_by_token(token, "admin")
|
|
163
|
+
roles = await micos_auth.get_roles("admin", "1001")
|
|
164
|
+
permissions = await micos_auth.get_permissions("admin", "1001")
|
|
165
|
+
data_scopes = await micos_auth.get_data_scopes_by_login_id("admin", "1001")
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## 8. 临时 token
|
|
169
|
+
|
|
170
|
+
创建:
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
temp = await micos_auth.create_temp_token(
|
|
174
|
+
"admin",
|
|
175
|
+
temp_id="file-1001",
|
|
176
|
+
type="download",
|
|
177
|
+
time=300,
|
|
178
|
+
extra={"filename": "report.xlsx"},
|
|
179
|
+
)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
校验:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
ok = await micos_auth.verify_temp_token(
|
|
186
|
+
temp["token"],
|
|
187
|
+
"admin",
|
|
188
|
+
type="download",
|
|
189
|
+
)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## 9. 会话查询与统计
|
|
193
|
+
|
|
194
|
+
当前查询模型:
|
|
195
|
+
|
|
196
|
+
- `session` 是 `login_id` 级聚合
|
|
197
|
+
- `token` 是具体登录明细
|
|
198
|
+
- `device` 是 token 分组维度
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
sessions = await micos_session.list_sessions("admin")
|
|
202
|
+
page = await micos_session.page_sessions("admin", current=1, size=20)
|
|
203
|
+
login_session = await micos_session.get_session("admin", "1001")
|
|
204
|
+
tokens = await micos_session.list_tokens("admin", "1001")
|
|
205
|
+
device_tokens = await micos_session.list_device_sessions("admin", "1001", "pc")
|
|
206
|
+
device_summaries = await micos_session.list_device_summaries("admin", "1001")
|
|
207
|
+
|
|
208
|
+
online_count = await micos_session.count_online_sessions("admin")
|
|
209
|
+
login_token_count = await micos_session.count_login_id_sessions("admin", "1001")
|
|
210
|
+
device_token_count = await micos_session.count_device_tokens("admin", "1001", "pc")
|
|
211
|
+
|
|
212
|
+
analysis = await micos_session.get_analysis()
|
|
213
|
+
chart = await micos_session.get_chart_data(days=7)
|
|
214
|
+
distribution = await micos_session.get_realm_distribution()
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
统计对象说明:
|
|
218
|
+
|
|
219
|
+
- `get_analysis()`
|
|
220
|
+
返回总登录数、总 token 数、总设备数、最近一小时新增 token 数
|
|
221
|
+
- `get_chart_data(days=7)`
|
|
222
|
+
返回按天统计的 token 创建趋势
|
|
223
|
+
- `get_realm_distribution()`
|
|
224
|
+
返回各 realm 的登录数、token 数、设备数分布
|
|
225
|
+
- `list_device_summaries("admin", "1001")`
|
|
226
|
+
直接返回某个 `login_id` 下各设备摘要,包括 token 数、最近登录时间、最近访问时间
|
|
227
|
+
|
|
228
|
+
## 10. 撤销与下线
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
await micos_auth.revoke_token("admin", token)
|
|
232
|
+
await micos_auth.revoke_login("admin", "1001")
|
|
233
|
+
await micos_auth.kickout_login_id("admin", "1001")
|
|
234
|
+
await micos_auth.kickout_device("admin", "1001", "pc")
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
兼容接口:
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
await micos_auth.logout_current("admin", token)
|
|
241
|
+
await micos_auth.logout_login_id("admin", "1001")
|
|
242
|
+
await micos_auth.logout_device("admin", "1001", "pc")
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## 11. Redis 存储模型
|
|
246
|
+
|
|
247
|
+
当前 Redis 主结构围绕 `realm_id + login_id`:
|
|
248
|
+
|
|
249
|
+
- `micosauth:{realm_id}:{login_id}:session`
|
|
250
|
+
登录主体聚合数据
|
|
251
|
+
- `micosauth:{realm_id}:{login_id}:tokens`
|
|
252
|
+
token 明细 `HASH`
|
|
253
|
+
- `micosauth:{realm_id}:{login_id}:device_tokens:{device_id}`
|
|
254
|
+
设备维度 token 明细 `HASH`
|
|
255
|
+
- `micosauth:{realm_id}:token_lookup:{token}`
|
|
256
|
+
token 反查 `login_id`
|
|
257
|
+
- `micosauth:{realm_id}:login_index`
|
|
258
|
+
realm 级 login 分布索引
|
|
259
|
+
- `micosauth:{realm_id}:token_index`
|
|
260
|
+
token 过期索引
|
|
261
|
+
- `micosauth:{realm_id}:created_index`
|
|
262
|
+
token 创建时间索引
|
|
263
|
+
- `micosauth:{realm_id}:temp:{token}`
|
|
264
|
+
临时 token
|
|
265
|
+
|
|
266
|
+
## 12. FastAPI 接入
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
from fastapi import FastAPI
|
|
270
|
+
from micosauth.adapters.fastapi import build_micosauth_lifespan, install_fastapi_auth
|
|
271
|
+
|
|
272
|
+
app = FastAPI(lifespan=build_micosauth_lifespan(micos_service))
|
|
273
|
+
install_fastapi_auth(app, micos_service)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
说明:
|
|
277
|
+
|
|
278
|
+
- FastAPI dependency 必须显式传 `realm`
|
|
279
|
+
- decorator 必须显式传 `realm`
|
|
280
|
+
- middleware 不做默认自动认证
|
|
281
|
+
- `micosauth` 不负责猜测 realm
|
|
282
|
+
|
|
283
|
+
示例:
|
|
284
|
+
|
|
285
|
+
```python
|
|
286
|
+
from fastapi import Depends
|
|
287
|
+
from micosauth.adapters.fastapi import require_login_dep
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
@app.get("/admin/me", dependencies=[Depends(require_login_dep(realm="admin"))])
|
|
291
|
+
async def admin_me():
|
|
292
|
+
return {"ok": True}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## 13. OR / AND 鉴权模式
|
|
296
|
+
|
|
297
|
+
角色和权限校验都支持:
|
|
298
|
+
|
|
299
|
+
- `AND`
|
|
300
|
+
- `OR`
|
|
301
|
+
- 权限支持通配符匹配
|
|
302
|
+
|
|
303
|
+
```python
|
|
304
|
+
await micos_auth.require_roles(token, ["ADMIN", "AUDITOR"], "admin", mode="AND")
|
|
305
|
+
await micos_auth.require_permissions(token, ["sys:user:*", "sys:log:view"], "admin", mode="OR")
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## 14. 当前状态
|
|
309
|
+
|
|
310
|
+
当前版本已经完成:
|
|
311
|
+
|
|
312
|
+
- Redis 真测
|
|
313
|
+
- FastAPI 集成真测
|
|
314
|
+
- 多 realm 接入真测
|
|
315
|
+
- 多设备、多 token 策略真测
|
|
316
|
+
- 设备摘要查询真测
|
|
317
|
+
- 角色、权限 `AND/OR` 模式测试
|
|
318
|
+
- 权限通配符测试
|
|
319
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# micosauth 发布说明
|
|
2
|
+
|
|
3
|
+
## 1. 发布前检查
|
|
4
|
+
|
|
5
|
+
发布到 PyPI 之前,至少完成以下检查:
|
|
6
|
+
|
|
7
|
+
1. 运行单元测试
|
|
8
|
+
2. 确认 `python -m compileall micosauth` 通过
|
|
9
|
+
3. 检查 `pyproject.toml` 已包含 `micosauth*`
|
|
10
|
+
4. 检查 `micosauth/docs/README.md` 是否同步最新用法
|
|
11
|
+
5. 确认版本号
|
|
12
|
+
6. 确认依赖项
|
|
13
|
+
|
|
14
|
+
## 2. 当前项目中的打包注意事项
|
|
15
|
+
|
|
16
|
+
当前仓库主项目名仍然是 `hei-fastapi`,不是独立的 `micosauth` 包仓库。
|
|
17
|
+
|
|
18
|
+
这意味着当前状态下:
|
|
19
|
+
|
|
20
|
+
- `micosauth` 已经可以被主项目一起打包
|
|
21
|
+
- 但还不是独立发布到 PyPI 的最终形态
|
|
22
|
+
|
|
23
|
+
如果要正式作为独立包发布,建议后续拆分为独立仓库,并调整:
|
|
24
|
+
|
|
25
|
+
- `[project].name`
|
|
26
|
+
- `[project].description`
|
|
27
|
+
- README
|
|
28
|
+
- classifiers
|
|
29
|
+
- 可选依赖
|
|
30
|
+
|
|
31
|
+
## 3. 当前已完成的基础验证
|
|
32
|
+
|
|
33
|
+
- `pytest -q micosauth/tests`
|
|
34
|
+
- `python -m compileall micosauth`
|
|
35
|
+
|
|
36
|
+
## 4. 建议的下一步
|
|
37
|
+
|
|
38
|
+
正式发布前,建议继续补齐:
|
|
39
|
+
|
|
40
|
+
- Redis 集成测试
|
|
41
|
+
- FastAPI 适配层测试
|
|
42
|
+
- 临时 token 集成测试
|
|
43
|
+
- 撤销 / 下线 / 多设备多 token 行为测试
|
|
44
|
+
- PyPI 元数据整理
|