Skip to content

Commit ed97d8b

Browse files
committed
完成user权限判断逻辑
修复多个prefetch字段的时候加载错误的问题
1 parent a6e916c commit ed97d8b

File tree

10 files changed

+113
-73
lines changed

10 files changed

+113
-73
lines changed

fast_tmp/admin/site.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,8 @@ class UserAdmin(ModelAdmin):
66
model = User
77
list_display = ("id", "username", "is_active")
88
inline = ("is_active",)
9-
create_fields = (
10-
"username",
11-
"password",
12-
"groups",
13-
)
14-
update_fields = ("groups",)
9+
create_fields = ("username", "password", "groups", "permissions")
10+
update_fields = ("groups", "permissions")
1511
# create_fields = (User.username, User.password)
1612
# update_fields = (User.password,)
1713

@@ -30,7 +26,8 @@ class UserAdmin(ModelAdmin):
3026

3127
class GroupAdmin(ModelAdmin):
3228
model = Group
33-
list_display = ("id", "name", "users")
34-
create_fields = ("name",)
29+
list_display = ("id", "name", "users", "permissions")
30+
create_fields = ("name", "permissions")
31+
update_fields = ("name", "permissions")
3532
# create_fields = (Group.name, Group.users)
3633
# update_fields = (Group.name, Group.users)

fast_tmp/contrib/auth/hashers.py

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,7 @@ def make_password(password, salt=None, hasher="default"):
8181

8282
@functools.lru_cache(maxsize=None)
8383
def get_hashers():
84-
hashers = []
85-
hashers.append(PBKDF2PasswordHasher())
86-
hashers.append(PBKDF2SHA1PasswordHasher)
87-
hashers.append(MD5PasswordHasher)
84+
hashers = [PBKDF2PasswordHasher(), PBKDF2SHA1PasswordHasher, MD5PasswordHasher]
8885
return hashers
8986

9087

@@ -476,10 +473,10 @@ def verify(self, password, encoded):
476473
def safe_summary(self, encoded):
477474
decoded = self.decode(encoded)
478475
return {
479-
("algorithm"): decoded["algorithm"],
480-
("work factor"): decoded["work_factor"],
481-
("salt"): mask_hash(decoded["salt"]),
482-
("checksum"): mask_hash(decoded["checksum"]),
476+
"algorithm": decoded["algorithm"],
477+
"work factor": decoded["work_factor"],
478+
"salt": mask_hash(decoded["salt"]),
479+
"checksum": mask_hash(decoded["checksum"]),
483480
}
484481

485482
def must_update(self, encoded):
@@ -569,12 +566,12 @@ def verify(self, password, encoded):
569566
def safe_summary(self, encoded):
570567
decoded = self.decode(encoded)
571568
return {
572-
("algorithm"): decoded["algorithm"],
573-
("work factor"): decoded["work_factor"],
574-
("block size"): decoded["block_size"],
575-
("parallelism"): decoded["parallelism"],
576-
("salt"): mask_hash(decoded["salt"]),
577-
("hash"): mask_hash(decoded["hash"]),
569+
"algorithm": decoded["algorithm"],
570+
"work factor": decoded["work_factor"],
571+
"block size": decoded["block_size"],
572+
"parallelism": decoded["parallelism"],
573+
"salt": mask_hash(decoded["salt"]),
574+
"hash": mask_hash(decoded["hash"]),
578575
}
579576

580577
def must_update(self, encoded):
@@ -620,9 +617,9 @@ def verify(self, password, encoded):
620617
def safe_summary(self, encoded):
621618
decoded = self.decode(encoded)
622619
return {
623-
("algorithm"): decoded["algorithm"],
624-
("salt"): mask_hash(decoded["salt"], show=2),
625-
("hash"): mask_hash(decoded["hash"]),
620+
"algorithm": decoded["algorithm"],
621+
"salt": mask_hash(decoded["salt"], show=2),
622+
"hash": mask_hash(decoded["hash"]),
626623
}
627624

628625
def must_update(self, encoded):

fast_tmp/depends/auth.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ async def authenticate_user(username: str, password: str) -> Optional[User]:
5555

5656
async def authenticate_active_user(username: str, password: str) -> Optional[User]:
5757
"""
58-
验证密码
58+
验证密码且用户为活跃用户
5959
"""
6060
user = await get_user(username)
6161
if not user or not user.is_active or not user.check_password(password):
@@ -113,12 +113,15 @@ async def get_current_active_user(current_user: User = Depends(get_current_user)
113113

114114

115115
async def get_superuser(current_user: User = Depends(get_current_active_user)):
116+
"""
117+
获取超级用户
118+
"""
116119
if not current_user.is_superuser:
117120
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN)
118121
return current_user
119122

120123

121-
def get_user_has_perms(perms: Optional[Tuple[str, ...]]):
124+
async def get_user_has_perms(perms: Optional[Tuple[str, ...]]):
122125
"""
123126
判定用户是否具有相关权限
124127
"""

fast_tmp/models.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,10 @@ async def has_perm(self, codename: str) -> bool:
9696
if self.is_superuser:
9797
return True
9898
if (
99-
await Permission.filter(Q(users__pk=self.pk) | Q(groups__users__pk=self.pk))
100-
.filter(codename=codename)
101-
.exists()
99+
await Permission.filter(users__pk=self.pk).filter(codename=codename).exists()
100+
or await Permission.filter(groups__users__pk=self.pk).filter(codename=codename).exists()
102101
):
103102
return True
104-
# if await Group.filter(users__pk=self.pk, permissions__codename=codename).exists():
105-
# return True
106103
return False
107104

108105
async def has_perms(self, codenames: Tuple[str, ...]) -> bool:
@@ -111,15 +108,16 @@ async def has_perms(self, codenames: Tuple[str, ...]) -> bool:
111108
"""
112109
if self.is_superuser:
113110
return True
114-
perms = (
115-
await Permission.filter(Q(users__pk=self.pk) | Q(groups__users__pk=self.pk))
116-
.filter(codename__in=codenames)
117-
.distinct()
118-
.values("codename")
119-
)
120-
if codenames == perms:
121-
return True
122-
return False
111+
perms1 = await Permission.filter(users__pk=self.pk)
112+
perms2 = await Permission.filter(groups__users__pk=self.pk)
113+
s = set([i.codename for i in perms2])
114+
for i in perms1:
115+
s.add(i.codename)
116+
117+
for i in codenames:
118+
if not i in s:
119+
return False
120+
return True
123121

124122
def __str__(self):
125123
return self.username

fast_tmp/site/__init__.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,12 +264,20 @@ def prefetch(
264264
"""
265265
判断是否需要额外预加载的数据
266266
"""
267+
select_list = []
268+
prefeth_list = []
267269
for field_name, field in fields.items():
268-
queryset = field.prefetch(request, queryset)
270+
d = field.prefetch()
271+
if d == "select":
272+
select_list.append(field_name)
273+
elif d == "prefetch":
274+
prefeth_list.append(field_name)
275+
if len(select_list) > 0:
276+
queryset = queryset.select_related(*select_list)
277+
elif len(prefeth_list) > 0:
278+
queryset = queryset.prefetch_related(*prefeth_list)
269279
return queryset
270280

271-
__list_sql = None
272-
273281
def queryset(self, request: Request):
274282
ret = self.model.all()
275283
return ret
@@ -299,8 +307,9 @@ async def get_instance(self, request: Request, pk: Any) -> Model:
299307
queryset = self.model.filter(pk=pk)
300308
queryset = self.prefetch(request, queryset, self.get_update_fields())
301309
instance = await queryset.first()
310+
302311
if instance is None:
303-
raise NotFoundError()
312+
raise NotFoundError("can not found instance:" + str(pk))
304313
return instance
305314

306315
def make_fields(self):
@@ -322,7 +331,7 @@ def make_fields(self):
322331
def get_control_field(self, name: str) -> BaseAdminControl:
323332
ret = self.fields.get(name)
324333
if ret is None:
325-
raise NotFoundError()
334+
raise NotFoundError("can not found field:" + name)
326335
return ret
327336

328337
def __init__(self, prefix: str = None):

fast_tmp/site/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ def list_queryset(self, queryset: QuerySet) -> QuerySet: # 列表
2222
"""
2323
return queryset
2424

25-
def prefetch(self, request: Request, queryset: QuerySet) -> QuerySet: # 列表
25+
def prefetch(self) -> Optional[str]: # 列表
2626
"""
2727
过滤规则,用于页面查询和过滤用
2828
要求值必须相等
2929
"""
30-
return queryset
30+
return None
3131

3232
async def get_value(self, request: Request, obj: Model) -> Any:
3333
"""

fast_tmp/site/util.py

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,8 @@ async def get_selects(
314314
data = await field_model_all
315315
return {"options": [{"value": i.pk, "label": str(i)} for i in data]}
316316

317-
def prefetch(self, request: Request, queryset: QuerySet) -> QuerySet:
318-
return queryset.select_related(self.name)
317+
def prefetch(self) -> Optional[str]:
318+
return "select"
319319

320320
def get_column_inline(self, request: Request) -> Column:
321321
raise AttributeError("foreignkey field can not be used in column inline.")
@@ -376,8 +376,8 @@ async def get_selects(
376376
data = await field_model_all
377377
return {"options": [{"value": i.pk, "label": str(i)} for i in data]}
378378

379-
def prefetch(self, request: Request, queryset: QuerySet) -> QuerySet:
380-
return queryset.select_related(self.name)
379+
def prefetch(self) -> Optional[str]:
380+
return "select"
381381

382382
def get_column(self, request: Request) -> Column:
383383
if not self._column:
@@ -422,8 +422,8 @@ class ManyToManyControl(BaseAdminControl, RelationSelectApi):
422422
_many = True
423423
_control_type = ControlEnum.select
424424

425-
def prefetch(self, request: Request, queryset: QuerySet) -> QuerySet:
426-
return queryset.prefetch_related(self.name)
425+
def prefetch(self) -> Optional[str]:
426+
return "prefetch"
427427

428428
def get_column(self, request: Request) -> Column:
429429
if not self._column:
@@ -483,8 +483,10 @@ def get_control(self, request: Request) -> Control:
483483
self._control.clearable = True
484484
return self._control
485485

486-
def amis_2_orm(self, value: Any) -> Any:
487-
return value.split(",")
486+
def amis_2_orm(self, value: List[dict]) -> Any:
487+
if isinstance(value, str):
488+
return value.split(",")
489+
return [i["value"] for i in value]
488490

489491
async def validate(self, value: Any) -> Any:
490492
if value is not None:
@@ -496,26 +498,26 @@ async def validate(self, value: Any) -> Any:
496498
async def set_value(self, request: Request, obj: Model, value: Any):
497499
value = await self.validate(value)
498500
field: fields.ManyToManyRelation = getattr(obj, self.name)
499-
if not field:
500-
raise NotFoundError()
501-
add = set()
502-
remove = set()
501+
# if not field:
502+
# raise NotFoundError()
503+
add_field = []
504+
remove_field = []
503505
for i in field:
504506
for j in value:
505507
if j.pk == i.pk:
506508
break
507509
else:
508-
remove.add(i)
510+
remove_field.append(i)
509511
for j in value:
510512
for i in field:
511513
if j.pk == i.pk:
512514
break
513515
else:
514-
add.add(j)
515-
if len(remove) > 0:
516-
await field.remove(*remove)
517-
if len(add) > 0:
518-
await field.add(*add)
516+
add_field.append(j)
517+
if len(remove_field) > 0:
518+
await field.remove(*remove_field)
519+
if len(add_field) > 0:
520+
await field.add(*add_field)
519521

520522
def get_column_inline(
521523
self, request: Request

fastapi_cli/__init__.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,31 @@ async def create_superuser(username: str, password: str):
2828
user = User(username=username, is_superuser=True)
2929
user.set_password(password)
3030
await user.save()
31-
print(f"创建{username}成功")
31+
sys.stdout.write(f"创建{username}成功")
32+
33+
34+
@async_to_sync
35+
async def make_permissions():
36+
from tortoise import Tortoise
37+
from fast_tmp.utils.model import get_all_models
38+
from fast_tmp.models import Permission
39+
await Tortoise.init(config=settings.TORTOISE_ORM)
40+
all_model = get_all_models()
41+
for model in all_model:
42+
model_name=model.__name__.lower()
43+
await Permission.get_or_create(codename=model_name + "_create", defaults={"label": f"{model_name}__创建"})
44+
await Permission.get_or_create(codename=model_name + "_update", defaults={"label": f"{model_name}__更新"})
45+
await Permission.get_or_create(codename=model_name + "_delete", defaults={"label": f"{model_name}__删除"})
46+
await Permission.get_or_create(codename=model_name + "_list", defaults={"label": f"{model_name}__修改"})
47+
sys.stdout.write("构建权限表完成")
48+
49+
50+
@app.command()
51+
def make_perm():
52+
"""
53+
同步所有model的权限
54+
"""
55+
make_permissions()
3256

3357

3458
@app.command()

task.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
~~8. 研究Request的user的作用~~
1212
9. 增加字段检查报错
1313
10. 字段名字为desc时页面显示名字为降序..
14+
11. 检查是否存在is_active为false的超级用户可以登录的情况
1415

1516
# admin管理页面缺少功能
1617

tests/test_example/app.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
11
import os
22

33
os.environ.setdefault("FASTAPI_SETTINGS_MODULE", "test_example.settings")
4+
5+
from fastapi import Depends
46
from test_example.admin import AuthorModel, BookModel, FieldTestingModel
57
from tortoise.contrib.fastapi import register_tortoise
68

79
from fast_tmp.conf import settings
10+
from fast_tmp.depends.auth import get_current_active_user
811
from fast_tmp.factory import create_app
12+
from fast_tmp.models import User
913
from fast_tmp.site import register_model_site
1014

1115
register_model_site({"fieldtesting": [FieldTestingModel(), BookModel(), AuthorModel()]})
1216
app = create_app()
1317
app.title = "test_example"
1418

15-
# @app.get("/perms")
16-
# async def get_perms(codename: str, user: Optional[User] = Depends(__get_user),
17-
# ):
18-
# """
19-
# 测试权限
20-
# """
19+
20+
@app.get("/perms")
21+
async def get_perms(
22+
codename: str,
23+
user: User = Depends(get_current_active_user),
24+
):
25+
"""
26+
测试权限
27+
"""
28+
print(await user.has_perms((codename,)))
29+
return await user.has_perm(codename)
2130

2231

2332
register_tortoise(app, config=settings.TORTOISE_ORM, generate_schemas=True)

0 commit comments

Comments
 (0)