feat: user admin cache

This commit is contained in:
xtaodada 2024-11-08 15:12:44 +08:00
parent 0f20fad339
commit 22014a7b0e
Signed by: xtaodada
GPG Key ID: 4CBB3F4FA8C85659
6 changed files with 64 additions and 9 deletions

View File

@ -76,7 +76,10 @@ var sa = {
return layer.alert('失败:' + res.msg);
},
success403: function(res){ // code=403, 代表权限不足
return layer.alert("权限不足," + res.msg, {icon: 5});
return layer.alert("权限不足," + res.msg, {icon: 5}, function () {
layer.closeAll();
return sa.$page.openLogin(cfg.login_url);
});
},
success401: function(res){ // code=401, 代表未登录
return layer.confirm("您当前暂未登录,是否立即登录?", {}, function(){
@ -88,6 +91,9 @@ var sa = {
if(xhr.status == 0){
return layer.alert('无法连接到服务器,请检查网络');
}
if (xhr.status == 403) {
return cfg.success403({msg: '请尝试重新登录'});
}
return layer.alert("异常:" + JSON.stringify(xhr));
},
complete: function(xhr, ts) { // 成功失败都会执行

View File

@ -1,3 +1,4 @@
import datetime
from typing import TYPE_CHECKING
from fastapi_amis_admin.crud import BaseApiOut
@ -123,5 +124,9 @@ class UserRoutes(Plugin):
token_info.roles = ",".join(
await self.user_role_services.get_user_roles(user.username)
)
response.set_cookie("Authorization", f"bearer {token_info.access_token}")
response.set_cookie(
"Authorization",
f"bearer {token_info.access_token}",
expires=datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=3),
)
return BaseApiOut(code=0, data=token_info)

View File

@ -18,7 +18,9 @@ class UserUpdateRoutes(Plugin):
_prefix = "/user"
def __init__(
self, user_services: UserServices, user_role_services: UserRoleServices
self,
user_services: UserServices,
user_role_services: UserRoleServices,
):
self.user_services = user_services
self.user_role_services = user_role_services
@ -69,7 +71,12 @@ class UserUpdateRoutes(Plugin):
@handler.get("/avatar/{uid}/{file_path}", student=True, out=True)
async def get_avatar(self, request: Request, uid: int, file_path: str):
if request.user.id != uid:
can_see = False
if await self.user_role_services.is_admin(request.user.username):
can_see = True
if request.user.id == uid:
can_see = True
if not can_see:
return BaseApiOut(status=500, msg="无权查看他人头像")
path = await get_avatar(uid, file_path)
if not path:

View File

@ -0,0 +1,26 @@
from typing import List
from persica.factory.component import AsyncInitializingComponent
from src.core.redis_db import RedisDB
class UserAdminCache(AsyncInitializingComponent):
def __init__(self, redis: RedisDB):
self.client = redis.client
self.qname = "users:admin"
async def ismember(self, username: str) -> bool:
return await self.client.sismember(self.qname, username)
async def get_all(self) -> List[str]:
return [str_data for str_data in await self.client.smembers(self.qname)]
async def set(self, username: str) -> bool:
return await self.client.sadd(self.qname, username)
async def remove(self, username: str) -> bool:
return await self.client.srem(self.qname, username)
async def remove_all(self) -> bool:
return await self.client.delete(self.qname)

View File

@ -1,4 +1,4 @@
from typing import Optional
from typing import Optional, List, Sequence
from fastapi_user_auth.auth import Auth
from fastapi_user_auth.auth.backends.redis import RedisTokenStore
@ -101,7 +101,7 @@ class UserRepo(AsyncInitializingComponent):
ptype: Optional[str] = None,
v0: Optional[str] = None,
v1: Optional[str] = None,
) -> Optional[RoleModel]:
) -> Sequence[CasbinRule]:
async with AsyncSession(self.engine) as session:
statement = select(self.rule_model)
if ptype:
@ -111,7 +111,7 @@ class UserRepo(AsyncInitializingComponent):
if v1:
statement = statement.where(self.rule_model.v1 == v1)
r = await session.exec(statement)
return r.first()
return r.all()
async def create_role_rule(self, rule: "CasbinRule") -> CasbinRule:
async with AsyncSession(self.engine) as session:

View File

@ -5,6 +5,7 @@ from fastapi_user_auth.utils.casbin import update_subject_roles
from persica.factory.component import AsyncInitializingComponent
from pydantic import SecretStr
from .cache import UserAdminCache
from .models import UserModel, RoleModel
from src.services.users.repositories import UserRepo
from .schemas import UserRoleEnum
@ -99,8 +100,9 @@ class UserServices(AsyncInitializingComponent):
class UserRoleServices(AsyncInitializingComponent):
__order__ = 1
def __init__(self, repo: UserRepo):
def __init__(self, repo: UserRepo, cache: UserAdminCache):
self.repo = repo
self.cache = cache
self.role_model = RoleModel
self.rule_model = CasbinRule
@ -112,6 +114,15 @@ class UserRoleServices(AsyncInitializingComponent):
if await self.get_role(key=key) is None:
await self.create_role(key, f"{key} role")
print(f"Create role: {key}")
await self.cache.remove_all()
for admin in await self.get_role_rule("g", None, "r:admin"):
await self.cache.set(admin.v0[2:])
async def is_admin(self, username: str) -> bool:
return await self.cache.ismember(username)
async def get_admin_list(self) -> List[str]:
return await self.cache.get_all()
async def get_role(
self, rid: Optional[int] = None, key: Optional[str] = None
@ -133,7 +144,7 @@ class UserRoleServices(AsyncInitializingComponent):
ptype: Optional[str] = None,
v0: Optional[str] = None,
v1: Optional[str] = None,
) -> Optional[RoleModel]:
) -> Sequence[CasbinRule]:
return await self.repo.get_role_rule(ptype, v0, v1)
async def is_user_in_role_group(