版本升级:
1. 新增(kinit-api,kinit-admin,kinit-uni):新增JWT刷新字段中间件,默认将refresh字段加入到response headers中存储 2. 更新(kinit-api):更新接口依赖库到最新版本 2. 优化(kinit-api):更新 OpenAuth 认证依赖项
This commit is contained in:
parent
e8979577bd
commit
a2bab19881
@ -66,13 +66,13 @@ service.interceptors.response.use(
|
||||
// 这个状态码是和后端约定好的
|
||||
const code = response.data.code || unauthorized_code
|
||||
const message = response.data.message || '后端接口无返回内容'
|
||||
const refresh = response.data.refresh || false
|
||||
const refresh = response.headers.refresh
|
||||
|
||||
if (response.config.responseType === 'blob') {
|
||||
// 如果是文件流,直接过
|
||||
return response
|
||||
} else if (code === result_code) {
|
||||
if (refresh) {
|
||||
if (refresh === '1') {
|
||||
// 因token快过期,刷新token
|
||||
refreshToken().then((res) => {
|
||||
const appStore = useAppStore()
|
||||
|
@ -43,7 +43,7 @@ Typer 官方文档:https://typer.tiangolo.com/
|
||||
|
||||
开发语言:Python 3.10
|
||||
|
||||
开发框架:Fastapi 0.94.1
|
||||
开发框架:Fastapi 0.95.0
|
||||
|
||||
## 开发工具
|
||||
|
||||
|
@ -11,7 +11,7 @@ from fastapi.security import OAuth2PasswordBearer
|
||||
"""
|
||||
系统版本
|
||||
"""
|
||||
VERSION = "1.6.4"
|
||||
VERSION = "1.7.0"
|
||||
|
||||
"""安全警告: 不要在生产中打开调试运行!"""
|
||||
DEBUG = True
|
||||
@ -132,4 +132,5 @@ MIDDLEWARES = [
|
||||
"core.middleware.register_request_log_middleware" if REQUEST_LOG_RECORD else None,
|
||||
"core.middleware.register_operation_record_middleware" if OPERATION_LOG_RECORD and MONGO_DB_ENABLE else None,
|
||||
"core.middleware.register_demo_env_middleware" if DEMO else None,
|
||||
"core.middleware.register_jwt_refresh_middleware"
|
||||
]
|
||||
|
@ -30,7 +30,7 @@ async def get_banners(auth: Auth = Depends(AllUserAuth())):
|
||||
"id": 3, "image": "https://ktianc.oss-cn-beijing.aliyuncs.com/kinit/system/banner/2022-11-09/banner3.png"
|
||||
},
|
||||
]
|
||||
return SuccessResponse(data, refresh=auth.refresh)
|
||||
return SuccessResponse(data)
|
||||
|
||||
|
||||
@app.get("/user/access/source/", summary="用户来源")
|
||||
@ -42,7 +42,7 @@ async def get_user_access_source(auth: Auth = Depends(AllUserAuth())):
|
||||
{"value": 135, "name": 'analysis.videoAdvertising'},
|
||||
{"value": 1548, "name": 'analysis.searchEngines'}
|
||||
]
|
||||
return SuccessResponse(data, refresh=auth.refresh)
|
||||
return SuccessResponse(data)
|
||||
|
||||
|
||||
@app.get("/weekly/user/activity/", summary="每周用户活跃量")
|
||||
@ -56,7 +56,7 @@ async def get_weekly_user_activity(auth: Auth = Depends(AllUserAuth())):
|
||||
{"value": 1322, "name": 'analysis.saturday'},
|
||||
{"value": 1324, "name": 'analysis.sunday'}
|
||||
]
|
||||
return SuccessResponse(data, refresh=auth.refresh)
|
||||
return SuccessResponse(data)
|
||||
|
||||
|
||||
@app.get("/monthly/sales/", summary="每月销售额")
|
||||
@ -75,4 +75,4 @@ async def get_monthly_sales(auth: Auth = Depends(AllUserAuth())):
|
||||
{"estimate": 118, "actual": 99, "name": 'analysis.november'},
|
||||
{"estimate": 123, "actual": 123, "name": 'analysis.december'}
|
||||
]
|
||||
return SuccessResponse(data, refresh=auth.refresh)
|
||||
return SuccessResponse(data)
|
||||
|
@ -4,9 +4,8 @@
|
||||
# @File : current.py
|
||||
# @IDE : PyCharm
|
||||
# @desc : 获取认证后的信息工具
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from typing import List, Optional
|
||||
import jwt
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import joinedload
|
||||
from apps.vadmin.auth.crud import UserDal
|
||||
@ -20,20 +19,6 @@ from core.database import db_getter
|
||||
from .validation.auth import Auth
|
||||
|
||||
|
||||
def get_user_permissions(user: VadminUser) -> set:
|
||||
"""
|
||||
获取员工用户所有权限列表
|
||||
"""
|
||||
if any([role.is_admin for role in user.roles]):
|
||||
return {'*.*.*'}
|
||||
permissions = set()
|
||||
for role_obj in user.roles:
|
||||
for menu in role_obj.menus:
|
||||
if menu.perms and not menu.disabled:
|
||||
permissions.add(menu.perms)
|
||||
return permissions
|
||||
|
||||
|
||||
class OpenAuth(AuthValidation):
|
||||
|
||||
"""
|
||||
@ -41,50 +26,6 @@ class OpenAuth(AuthValidation):
|
||||
认证了以后可以获取到用户信息,无认证则获取不到
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def validate_token(cls, request: Request, token: str | None) -> str | None:
|
||||
"""
|
||||
验证用户 token,没有则返回 None
|
||||
"""
|
||||
if not token:
|
||||
return None
|
||||
try:
|
||||
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
|
||||
telephone: str = payload.get("sub")
|
||||
exp: int = payload.get("exp")
|
||||
is_refresh: bool = payload.get("is_refresh")
|
||||
if telephone is None or is_refresh:
|
||||
return None
|
||||
# 计算当前时间 + 缓冲时间是否大于等于 JWT 过期时间
|
||||
buffer_time = (datetime.now() + timedelta(minutes=settings.ACCESS_TOKEN_CACHE_MINUTES)).timestamp()
|
||||
if buffer_time >= exp:
|
||||
request.scope["refresh"] = True
|
||||
else:
|
||||
request.scope["refresh"] = False
|
||||
except jwt.exceptions.InvalidSignatureError:
|
||||
return None
|
||||
except jwt.exceptions.ExpiredSignatureError:
|
||||
return None
|
||||
return telephone
|
||||
|
||||
@classmethod
|
||||
async def validate_user(cls, request: Request, user: VadminUser, db: AsyncSession) -> Auth:
|
||||
"""
|
||||
验证用户信息
|
||||
"""
|
||||
if user is None:
|
||||
return Auth(db=db)
|
||||
elif not user.is_active:
|
||||
return Auth(db=db)
|
||||
request.scope["user_id"] = user.id
|
||||
request.scope["user_name"] = user.name
|
||||
request.scope["telephone"] = user.telephone
|
||||
try:
|
||||
request.scope["body"] = await request.body()
|
||||
except RuntimeError:
|
||||
request.scope["body"] = "获取失败"
|
||||
return Auth(user=user, db=db)
|
||||
|
||||
async def __call__(
|
||||
self,
|
||||
request: Request,
|
||||
@ -94,10 +35,13 @@ class OpenAuth(AuthValidation):
|
||||
"""
|
||||
每次调用依赖此类的接口会执行该方法
|
||||
"""
|
||||
if not settings.OAUTH_ENABLE:
|
||||
return Auth(db=db)
|
||||
try:
|
||||
telephone = self.validate_token(request, token)
|
||||
if telephone:
|
||||
user = await UserDal(db).get_data(telephone=telephone, v_return_none=True)
|
||||
return await self.validate_user(request, user, db)
|
||||
except CustomException:
|
||||
return Auth(db=db)
|
||||
|
||||
|
||||
@ -120,8 +64,6 @@ class AllUserAuth(AuthValidation):
|
||||
if not settings.OAUTH_ENABLE:
|
||||
return Auth(db=db)
|
||||
telephone = self.validate_token(request, token)
|
||||
if isinstance(telephone, Auth):
|
||||
return telephone
|
||||
user = await UserDal(db).get_data(telephone=telephone, v_return_none=True)
|
||||
return await self.validate_user(request, user, db)
|
||||
|
||||
@ -152,12 +94,10 @@ class FullAdminAuth(AuthValidation):
|
||||
if not settings.OAUTH_ENABLE:
|
||||
return Auth(db=db)
|
||||
telephone = self.validate_token(request, token)
|
||||
if isinstance(telephone, Auth):
|
||||
return telephone
|
||||
options = [joinedload(VadminUser.roles), joinedload("roles.menus")]
|
||||
user = await UserDal(db).get_data(telephone=telephone, v_return_none=True, v_options=options, is_staff=True)
|
||||
result = await self.validate_user(request, user, db)
|
||||
permissions = get_user_permissions(user)
|
||||
permissions = self.get_user_permissions(user)
|
||||
if permissions != {'*.*.*'} and self.permissions:
|
||||
if not (self.permissions & permissions):
|
||||
raise CustomException(msg="无权限操作", code=status.HTTP_403_FORBIDDEN)
|
||||
|
@ -4,20 +4,20 @@
|
||||
# @File : auth.py
|
||||
# @IDE : PyCharm
|
||||
# @desc : 用户凭证验证装饰器
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from fastapi import Request
|
||||
import jwt
|
||||
from pydantic import BaseModel
|
||||
from application import settings
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from apps.vadmin.auth import models
|
||||
from apps.vadmin.auth.models import VadminUser
|
||||
from core.exception import CustomException
|
||||
from utils import status
|
||||
from datetime import timedelta, datetime
|
||||
|
||||
|
||||
class Auth(BaseModel):
|
||||
user: models.VadminUser = None
|
||||
refresh: bool = False
|
||||
user: VadminUser = None
|
||||
db: AsyncSession
|
||||
|
||||
class Config:
|
||||
@ -33,7 +33,7 @@ class AuthValidation:
|
||||
error_code = status.HTTP_401_UNAUTHORIZED
|
||||
|
||||
@classmethod
|
||||
def validate_token(cls, request: Request, token: str) -> str:
|
||||
def validate_token(cls, request: Request, token: str | None) -> str:
|
||||
"""
|
||||
验证用户 token
|
||||
"""
|
||||
@ -52,9 +52,9 @@ class AuthValidation:
|
||||
# print("当前时间", buffer_time, datetime.fromtimestamp(buffer_time))
|
||||
# print("剩余时间", exp - buffer_time)
|
||||
if buffer_time >= exp:
|
||||
request.scope["refresh"] = True
|
||||
request.scope["refresh"] = 1
|
||||
else:
|
||||
request.scope["refresh"] = False
|
||||
request.scope["refresh"] = 0
|
||||
except jwt.exceptions.InvalidSignatureError:
|
||||
raise CustomException(msg="无效认证,请您重新登录", code=cls.error_code)
|
||||
except jwt.exceptions.ExpiredSignatureError:
|
||||
@ -62,7 +62,7 @@ class AuthValidation:
|
||||
return telephone
|
||||
|
||||
@classmethod
|
||||
async def validate_user(cls, request: Request, user: models.VadminUser, db: AsyncSession) -> Auth:
|
||||
async def validate_user(cls, request: Request, user: VadminUser, db: AsyncSession) -> Auth:
|
||||
"""
|
||||
验证用户信息
|
||||
"""
|
||||
@ -70,12 +70,25 @@ class AuthValidation:
|
||||
raise CustomException(msg="未认证,请您重新登陆", code=cls.error_code, status_code=cls.error_code)
|
||||
elif not user.is_active:
|
||||
raise CustomException(msg="用户已被冻结!", code=cls.error_code, status_code=cls.error_code)
|
||||
request.scope["telephone"] = user.telephone
|
||||
request.scope["user_id"] = user.id
|
||||
request.scope["user_name"] = user.name
|
||||
request.scope["telephone"] = user.telephone
|
||||
try:
|
||||
request.scope["body"] = await request.body()
|
||||
except RuntimeError:
|
||||
request.scope["body"] = "获取失败"
|
||||
refresh = request.scope.get("refresh", False)
|
||||
return Auth(user=user, db=db, refresh=refresh)
|
||||
return Auth(user=user, db=db)
|
||||
|
||||
@classmethod
|
||||
def get_user_permissions(cls, user: VadminUser) -> set:
|
||||
"""
|
||||
获取员工用户所有权限列表
|
||||
"""
|
||||
if any([role.is_admin for role in user.roles]):
|
||||
return {'*.*.*'}
|
||||
permissions = set()
|
||||
for role_obj in user.roles:
|
||||
for menu in role_obj.menus:
|
||||
if menu.perms and not menu.disabled:
|
||||
permissions.add(menu.perms)
|
||||
return permissions
|
||||
|
@ -11,7 +11,7 @@ from sqlalchemy.orm import joinedload
|
||||
from utils.response import SuccessResponse, ErrorResponse
|
||||
from . import schemas, crud, models
|
||||
from core.dependencies import IdList
|
||||
from apps.vadmin.auth.utils.current import AllUserAuth, get_user_permissions, FullAdminAuth
|
||||
from apps.vadmin.auth.utils.current import AllUserAuth, FullAdminAuth
|
||||
from apps.vadmin.auth.utils.validation.auth import Auth
|
||||
from .params import UserParams, RoleParams
|
||||
|
||||
@ -31,12 +31,12 @@ async def get_users(
|
||||
schema = schemas.UserOut
|
||||
datas = await crud.UserDal(auth.db).get_datas(**params.dict(), v_options=options, v_schema=schema)
|
||||
count = await crud.UserDal(auth.db).get_count(**params.to_count())
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.post("/users/", summary="创建用户")
|
||||
async def create_user(data: schemas.UserIn, auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.create"]))):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).create_data(data=data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.UserDal(auth.db).create_data(data=data))
|
||||
|
||||
|
||||
@app.delete("/users/", summary="批量删除用户", description="软删除,删除后清空所关联的角色")
|
||||
@ -46,7 +46,7 @@ async def delete_users(ids: IdList = Depends(), auth: Auth = Depends(FullAdminAu
|
||||
elif 1 in ids.ids:
|
||||
return ErrorResponse("不能删除超级管理员用户")
|
||||
await crud.UserDal(auth.db).delete_datas(ids=ids.ids, v_soft=True, is_active=False)
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
return SuccessResponse("删除成功")
|
||||
|
||||
|
||||
@app.put("/users/{data_id}/", summary="更新用户信息")
|
||||
@ -55,7 +55,7 @@ async def put_user(
|
||||
data: schemas.UserUpdate,
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.update"]))
|
||||
):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.UserDal(auth.db).put_data(data_id, data))
|
||||
|
||||
|
||||
@app.get("/users/{data_id}/", summary="获取用户信息")
|
||||
@ -66,32 +66,29 @@ async def get_user(
|
||||
model = models.VadminUser
|
||||
options = [joinedload(model.roles)]
|
||||
schema = schemas.UserOut
|
||||
return SuccessResponse(
|
||||
await crud.UserDal(auth.db).get_data(data_id, options, v_schema=schema),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
return SuccessResponse(await crud.UserDal(auth.db).get_data(data_id, options, v_schema=schema))
|
||||
|
||||
|
||||
@app.post("/user/current/reset/password/", summary="重置当前用户密码")
|
||||
async def user_current_reset_password(data: schemas.ResetPwd, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).reset_current_password(auth.user, data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.UserDal(auth.db).reset_current_password(auth.user, data))
|
||||
|
||||
|
||||
@app.post("/user/current/update/info/", summary="更新当前用户基本信息")
|
||||
async def post_user_current_update_info(data: schemas.UserUpdateBaseInfo, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).update_current_info(auth.user, data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.UserDal(auth.db).update_current_info(auth.user, data))
|
||||
|
||||
|
||||
@app.post("/user/current/update/avatar/", summary="更新当前用户头像")
|
||||
async def post_user_current_update_avatar(file: UploadFile, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).update_current_avatar(auth.user, file), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.UserDal(auth.db).update_current_avatar(auth.user, file))
|
||||
|
||||
|
||||
@app.get("/user/admin/current/info/", summary="获取当前管理员信息")
|
||||
async def get_user_admin_current_info(auth: Auth = Depends(FullAdminAuth())):
|
||||
result = schemas.UserOut.from_orm(auth.user).dict()
|
||||
result["permissions"] = list(get_user_permissions(auth.user))
|
||||
return SuccessResponse(result, refresh=auth.refresh)
|
||||
result["permissions"] = list(FullAdminAuth.get_user_permissions(auth.user))
|
||||
return SuccessResponse(result)
|
||||
|
||||
|
||||
@app.post("/user/export/query/list/to/excel/", summary="导出用户查询列表为excel")
|
||||
@ -100,17 +97,17 @@ async def post_user_export_query_list(
|
||||
params: UserParams = Depends(),
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.export"]))
|
||||
):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).export_query_list(header, params), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.UserDal(auth.db).export_query_list(header, params))
|
||||
|
||||
|
||||
@app.get("/user/download/import/template/", summary="下载最新批量导入用户模板")
|
||||
async def get_user_download_new_import_template(auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).download_import_template(), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.UserDal(auth.db).download_import_template())
|
||||
|
||||
|
||||
@app.post("/import/users/", summary="批量导入用户")
|
||||
async def post_import_users(file: UploadFile, auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.import"]))):
|
||||
return SuccessResponse(await crud.UserDal(auth.db).import_users(file), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.UserDal(auth.db).import_users(file))
|
||||
|
||||
|
||||
@app.post("/users/init/password/send/sms/", summary="初始化所选用户密码并发送通知短信")
|
||||
@ -119,16 +116,13 @@ async def post_users_init_password(
|
||||
ids: IdList = Depends(),
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.reset"]))
|
||||
):
|
||||
return SuccessResponse(
|
||||
await crud.UserDal(auth.db).init_password_send_sms(ids.ids, request.app.state.redis),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
return SuccessResponse(await crud.UserDal(auth.db).init_password_send_sms(ids.ids, request.app.state.redis))
|
||||
|
||||
|
||||
@app.put("/users/wx/server/openid/", summary="更新当前用户服务端微信平台openid")
|
||||
async def put_user_wx_server_openid(request: Request, code: str, auth: Auth = Depends(AllUserAuth())):
|
||||
result = await crud.UserDal(auth.db).update_wx_server_openid(code, auth.user, request.app.state.redis)
|
||||
return SuccessResponse(result, refresh=auth.refresh)
|
||||
return SuccessResponse(result)
|
||||
|
||||
|
||||
###########################################################
|
||||
@ -141,12 +135,12 @@ async def get_roles(
|
||||
):
|
||||
datas = await crud.RoleDal(auth.db).get_datas(**params.dict())
|
||||
count = await crud.RoleDal(auth.db).get_count(**params.to_count())
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.post("/roles/", summary="创建角色信息")
|
||||
async def create_role(role: schemas.RoleIn, auth: Auth = Depends(FullAdminAuth(permissions=["auth.role.create"]))):
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).create_data(data=role), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).create_data(data=role))
|
||||
|
||||
|
||||
@app.delete("/roles/", summary="批量删除角色", description="硬删除, 如果存在用户关联则无法删除")
|
||||
@ -154,7 +148,7 @@ async def delete_roles(ids: IdList = Depends(), auth: Auth = Depends(FullAdminAu
|
||||
if 1 in ids.ids:
|
||||
return ErrorResponse("不能删除管理员角色")
|
||||
await crud.RoleDal(auth.db).delete_datas(ids.ids, v_soft=False)
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
return SuccessResponse("删除成功")
|
||||
|
||||
|
||||
@app.put("/roles/{data_id}/", summary="更新角色信息")
|
||||
@ -165,12 +159,12 @@ async def put_role(
|
||||
):
|
||||
if 1 == data_id:
|
||||
return ErrorResponse("不能修改管理员角色")
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).put_data(data_id, data))
|
||||
|
||||
|
||||
@app.get("/roles/options/", summary="获取角色选择项")
|
||||
async def get_role_options(auth: Auth = Depends(FullAdminAuth(permissions=["auth.user.create", "auth.user.update"]))):
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).get_select_datas(), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).get_select_datas())
|
||||
|
||||
|
||||
@app.get("/roles/{data_id}/", summary="获取角色信息")
|
||||
@ -181,10 +175,7 @@ async def get_role(
|
||||
model = models.VadminRole
|
||||
options = [joinedload(model.menus)]
|
||||
schema = schemas.RoleOut
|
||||
return SuccessResponse(
|
||||
await crud.RoleDal(auth.db).get_data(data_id, options, v_schema=schema),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
return SuccessResponse(await crud.RoleDal(auth.db).get_data(data_id, options, v_schema=schema))
|
||||
|
||||
|
||||
###########################################################
|
||||
@ -193,33 +184,33 @@ async def get_role(
|
||||
@app.get("/menus/", summary="获取菜单列表")
|
||||
async def get_menus(auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.list"]))):
|
||||
datas = await crud.MenuDal(auth.db).get_tree_list(mode=1)
|
||||
return SuccessResponse(datas, refresh=auth.refresh)
|
||||
return SuccessResponse(datas)
|
||||
|
||||
|
||||
@app.get("/menus/tree/options/", summary="获取菜单树选择项,添加/修改菜单时使用")
|
||||
async def get_menus_options(auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.create", "auth.menu.update"]))):
|
||||
datas = await crud.MenuDal(auth.db).get_tree_list(mode=2)
|
||||
return SuccessResponse(datas, refresh=auth.refresh)
|
||||
return SuccessResponse(datas)
|
||||
|
||||
|
||||
@app.get("/menus/role/tree/options/", summary="获取菜单列表树信息,角色权限使用")
|
||||
async def get_menus_treeselect(
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.role.create", "auth.role.update"]))
|
||||
):
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).get_tree_list(mode=3), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).get_tree_list(mode=3))
|
||||
|
||||
|
||||
@app.post("/menus/", summary="创建菜单信息")
|
||||
async def create_menu(menu: schemas.Menu, auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.create"]))):
|
||||
if menu.parent_id:
|
||||
menu.alwaysShow = False
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).create_data(data=menu), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).create_data(data=menu))
|
||||
|
||||
|
||||
@app.delete("/menus/", summary="批量删除菜单", description="硬删除, 如果存在角色关联则无法删除")
|
||||
async def delete_menus(ids: IdList = Depends(), auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.delete"]))):
|
||||
await crud.MenuDal(auth.db).delete_datas(ids.ids, v_soft=False)
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
return SuccessResponse("删除成功")
|
||||
|
||||
|
||||
@app.put("/menus/{data_id}/", summary="更新菜单信息")
|
||||
@ -227,7 +218,7 @@ async def put_menus(
|
||||
data_id: int,
|
||||
data: schemas.Menu, auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.update"]))
|
||||
):
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).put_data(data_id, data))
|
||||
|
||||
|
||||
@app.get("/menus/{data_id}/", summary="获取菜单信息")
|
||||
@ -236,7 +227,7 @@ async def put_menus(
|
||||
auth: Auth = Depends(FullAdminAuth(permissions=["auth.menu.view", "auth.menu.update"]))
|
||||
):
|
||||
schema = schemas.MenuSimpleOut
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).get_data(data_id, None, v_schema=schema), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.MenuDal(auth.db).get_data(data_id, None, v_schema=schema))
|
||||
|
||||
|
||||
@app.get("/role/menus/tree/{role_id}/", summary="获取菜单列表树信息以及角色菜单权限ID,角色权限使用")
|
||||
@ -246,4 +237,4 @@ async def get_role_menu_tree(
|
||||
):
|
||||
treeselect = await crud.MenuDal(auth.db).get_tree_list(mode=3)
|
||||
role_menu_tree = await crud.RoleDal(auth.db).get_role_menu_tree(role_id)
|
||||
return SuccessResponse({"role_menu_tree": role_menu_tree, "menus": treeselect}, refresh=auth.refresh)
|
||||
return SuccessResponse({"role_menu_tree": role_menu_tree, "menus": treeselect})
|
||||
|
@ -29,42 +29,36 @@ async def get_issue_categorys(p: params.IssueCategoryParams = Depends(), auth: A
|
||||
schema = schemas.IssueCategoryListOut
|
||||
datas = await crud.IssueCategoryDal(auth.db).get_datas(**p.dict(), v_options=options, v_schema=schema)
|
||||
count = await crud.IssueCategoryDal(auth.db).get_count(**p.to_count())
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.get("/issue/categorys/options/", summary="获取类别选择项")
|
||||
async def get_issue_categorys_options(auth: Auth = Depends(AllUserAuth())):
|
||||
schema = schemas.IssueCategoryOptionsOut
|
||||
return SuccessResponse(
|
||||
await crud.IssueCategoryDal(auth.db).get_datas(limit=0, is_active=True, v_schema=schema),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).get_datas(limit=0, is_active=True, v_schema=schema))
|
||||
|
||||
|
||||
@app.post("/issue/categorys/", summary="创建类别")
|
||||
async def create_issue_category(data: schemas.IssueCategory, auth: Auth = Depends(AllUserAuth())):
|
||||
data.user_id = auth.user.id
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).create_data(data=data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).create_data(data=data))
|
||||
|
||||
|
||||
@app.delete("/issue/categorys/", summary="批量删除类别", description="硬删除")
|
||||
async def delete_issue_categorys(ids: IdList = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
await crud.IssueCategoryDal(auth.db).delete_datas(ids=ids.ids, v_soft=False)
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
return SuccessResponse("删除成功")
|
||||
|
||||
|
||||
@app.put("/issue/categorys/{data_id}/", summary="更新类别信息")
|
||||
async def put_issue_category(data_id: int, data: schemas.IssueCategory, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).put_data(data_id, data))
|
||||
|
||||
|
||||
@app.get("/issue/categorys/{data_id}/", summary="获取类别信息")
|
||||
async def get_issue_category(data_id: int, auth: Auth = Depends(AllUserAuth())):
|
||||
schema = schemas.IssueCategorySimpleOut
|
||||
return SuccessResponse(
|
||||
await crud.IssueCategoryDal(auth.db).get_data(data_id, v_schema=schema),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
return SuccessResponse(await crud.IssueCategoryDal(auth.db).get_data(data_id, v_schema=schema))
|
||||
|
||||
|
||||
@app.get("/issue/categorys/platform/{platform}/", summary="获取平台中的常见问题类别列表")
|
||||
@ -87,24 +81,24 @@ async def get_issues(p: params.IssueParams = Depends(), auth: Auth = Depends(All
|
||||
schema = schemas.IssueListOut
|
||||
datas = await crud.IssueDal(auth.db).get_datas(**p.dict(), v_options=options, v_schema=schema)
|
||||
count = await crud.IssueDal(auth.db).get_count(**p.to_count())
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.post("/issues/", summary="创建问题")
|
||||
async def create_issue(data: schemas.Issue, auth: Auth = Depends(AllUserAuth())):
|
||||
data.user_id = auth.user.id
|
||||
return SuccessResponse(await crud.IssueDal(auth.db).create_data(data=data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.IssueDal(auth.db).create_data(data=data))
|
||||
|
||||
|
||||
@app.delete("/issues/", summary="批量删除问题", description="硬删除")
|
||||
async def delete_issues(ids: IdList = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
await crud.IssueDal(auth.db).delete_datas(ids=ids.ids, v_soft=False)
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
return SuccessResponse("删除成功")
|
||||
|
||||
|
||||
@app.put("/issues/{data_id}/", summary="更新问题信息")
|
||||
async def put_issue(data_id: int, data: schemas.Issue, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.IssueDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.IssueDal(auth.db).put_data(data_id, data))
|
||||
|
||||
|
||||
@app.get("/issues/{data_id}/", summary="获取问题信息")
|
||||
|
@ -23,22 +23,25 @@ app = APIRouter()
|
||||
async def get_record_login(p: LoginParams = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
datas = await crud.LoginRecordDal(auth.db).get_datas(**p.dict())
|
||||
count = await crud.LoginRecordDal(auth.db).get_count(**p.to_count())
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.get("/operations/", summary="获取操作日志列表")
|
||||
async def get_record_operation(p: OperationParams = Depends(), db: DatabaseManage = Depends(get_database),
|
||||
auth: Auth = Depends(AllUserAuth())):
|
||||
async def get_record_operation(
|
||||
p: OperationParams = Depends(),
|
||||
db: DatabaseManage = Depends(get_database),
|
||||
auth: Auth = Depends(AllUserAuth())
|
||||
):
|
||||
count = await db.get_count("operation_record", **p.to_count())
|
||||
datas = await db.get_datas("operation_record", v_schema=schemas.OpertionRecordSimpleOut, **p.dict())
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.get("/sms/send/list/", summary="获取短信发送列表")
|
||||
async def get_sms_send_list(p: SMSParams = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
datas = await crud.SMSSendRecordDal(auth.db).get_datas(**p.dict())
|
||||
count = await crud.SMSSendRecordDal(auth.db).get_count(**p.to_count())
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
###########################################################
|
||||
@ -46,4 +49,4 @@ async def get_sms_send_list(p: SMSParams = Depends(), auth: Auth = Depends(AllUs
|
||||
###########################################################
|
||||
@app.get("/analysis/user/login/distribute/", summary="获取用户登录分布情况列表")
|
||||
async def get_user_login_distribute(auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.LoginRecordDal(auth.db).get_user_distribute(), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.LoginRecordDal(auth.db).get_user_distribute())
|
||||
|
@ -31,18 +31,18 @@ app = APIRouter()
|
||||
async def get_dict_types(p: DictTypeParams = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
datas = await crud.DictTypeDal(auth.db).get_datas(**p.dict())
|
||||
count = await crud.DictTypeDal(auth.db).get_count(**p.to_count())
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.post("/dict/types/", summary="创建字典类型")
|
||||
async def create_dict_types(data: schemas.DictType, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).create_data(data=data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).create_data(data=data))
|
||||
|
||||
|
||||
@app.delete("/dict/types/", summary="批量删除字典类型")
|
||||
async def delete_dict_types(ids: IdList = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
await crud.DictTypeDal(auth.db).delete_datas(ids=ids.ids)
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
return SuccessResponse("删除成功")
|
||||
|
||||
|
||||
@app.post("/dict/types/details/", summary="获取多个字典类型下的字典元素列表")
|
||||
@ -51,17 +51,17 @@ async def post_dicts_details(
|
||||
dict_types: List[str] = Body(None, title="字典元素列表", description="查询字典元素列表")
|
||||
):
|
||||
datas = await crud.DictTypeDal(auth.db).get_dicts_details(dict_types)
|
||||
return SuccessResponse(datas, refresh=auth.refresh)
|
||||
return SuccessResponse(datas)
|
||||
|
||||
|
||||
@app.get("/dict/types/options/", summary="获取字典类型选择项")
|
||||
async def get_dicts_options(auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).get_select_datas(), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).get_select_datas())
|
||||
|
||||
|
||||
@app.put("/dict/types/{data_id}/", summary="更新字典类型")
|
||||
async def put_dict_types(data_id: int, data: schemas.DictType, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.DictTypeDal(auth.db).put_data(data_id, data))
|
||||
|
||||
|
||||
@app.get("/dict/types/{data_id}/", summary="获取字典类型详细")
|
||||
@ -78,7 +78,7 @@ async def get_dict_type(data_id: int, auth: Auth = Depends(AllUserAuth())):
|
||||
###########################################################
|
||||
@app.post("/dict/details/", summary="创建字典元素")
|
||||
async def create_dict_details(data: schemas.DictDetails, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.DictDetailsDal(auth.db).create_data(data=data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.DictDetailsDal(auth.db).create_data(data=data))
|
||||
|
||||
|
||||
@app.get("/dict/details/", summary="获取单个字典类型下的字典元素列表,分页")
|
||||
@ -87,18 +87,18 @@ async def get_dict_details(params: DictDetailParams = Depends(), auth: Auth = De
|
||||
return ErrorResponse(msg="未获取到字典类型!")
|
||||
datas = await crud.DictDetailsDal(auth.db).get_datas(**params.dict())
|
||||
count = await crud.DictDetailsDal(auth.db).get_count(**params.to_count())
|
||||
return SuccessResponse(datas, count=count, refresh=auth.refresh)
|
||||
return SuccessResponse(datas, count=count)
|
||||
|
||||
|
||||
@app.delete("/dict/details/", summary="批量删除字典元素", description="硬删除")
|
||||
async def delete_dict_details(ids: IdList = Depends(), auth: Auth = Depends(AllUserAuth())):
|
||||
await crud.DictDetailsDal(auth.db).delete_datas(ids.ids, v_soft=False)
|
||||
return SuccessResponse("删除成功", refresh=auth.refresh)
|
||||
return SuccessResponse("删除成功")
|
||||
|
||||
|
||||
@app.put("/dict/details/{data_id}/", summary="更新字典元素")
|
||||
async def put_dict_details(data_id: int, data: schemas.DictDetails, auth: Auth = Depends(AllUserAuth())):
|
||||
return SuccessResponse(await crud.DictDetailsDal(auth.db).put_data(data_id, data), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.DictDetailsDal(auth.db).put_data(data_id, data))
|
||||
|
||||
|
||||
@app.get("/dict/details/{data_id}/", summary="获取字典元素详情")
|
||||
@ -142,23 +142,17 @@ async def sms_send(request: Request, telephone: str):
|
||||
###########################################################
|
||||
@app.get("/settings/tabs/", summary="获取系统配置标签列表")
|
||||
async def get_settings_tabs(classify: str, auth: Auth = Depends(FullAdminAuth())):
|
||||
return SuccessResponse(
|
||||
await crud.SettingsTabDal(auth.db).get_datas(limit=0, classify=classify),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
return SuccessResponse(await crud.SettingsTabDal(auth.db).get_datas(limit=0, classify=classify))
|
||||
|
||||
|
||||
@app.get("/settings/tabs/values/", summary="获取系统配置标签下的信息")
|
||||
async def get_settings_tabs_values(tab_id: int, auth: Auth = Depends(FullAdminAuth())):
|
||||
return SuccessResponse(await crud.SettingsDal(auth.db).get_tab_values(tab_id=tab_id), refresh=auth.refresh)
|
||||
return SuccessResponse(await crud.SettingsDal(auth.db).get_tab_values(tab_id=tab_id))
|
||||
|
||||
|
||||
@app.put("/settings/tabs/values/", summary="更新系统配置信息")
|
||||
async def put_settings_tabs_values(request: Request, datas: dict = Body(...), auth: Auth = Depends(FullAdminAuth())):
|
||||
return SuccessResponse(
|
||||
await crud.SettingsDal(auth.db).update_datas(datas, request.app.state.redis),
|
||||
refresh=auth.refresh
|
||||
)
|
||||
return SuccessResponse(await crud.SettingsDal(auth.db).update_datas(datas, request.app.state.redis))
|
||||
|
||||
|
||||
@app.get("/settings/base/config/", summary="获取系统基础配置", description="每次进入系统中时使用")
|
||||
@ -168,15 +162,9 @@ async def get_setting_base_config(db: AsyncSession = Depends(db_getter)):
|
||||
|
||||
@app.get("/settings/privacy/", summary="获取隐私协议")
|
||||
async def get_settings_privacy(auth: Auth = Depends(FullAdminAuth())):
|
||||
return SuccessResponse(
|
||||
(await crud.SettingsDal(auth.db).get_data(config_key="web_privacy")).config_value,
|
||||
refresh=auth.refresh
|
||||
)
|
||||
return SuccessResponse((await crud.SettingsDal(auth.db).get_data(config_key="web_privacy")).config_value)
|
||||
|
||||
|
||||
@app.get("/settings/agreement/", summary="获取用户协议")
|
||||
async def get_settings_agreement(auth: Auth = Depends(FullAdminAuth())):
|
||||
return SuccessResponse(
|
||||
(await crud.SettingsDal(auth.db).get_data(config_key="web_agreement")).config_value,
|
||||
refresh=auth.refresh
|
||||
)
|
||||
return SuccessResponse((await crud.SettingsDal(auth.db).get_data(config_key="web_agreement")).config_value)
|
||||
|
@ -13,7 +13,6 @@ import datetime
|
||||
import json
|
||||
import time
|
||||
from fastapi import Request, Response
|
||||
from core.exception import CustomException
|
||||
from core.logger import logger
|
||||
from fastapi import FastAPI
|
||||
from fastapi.routing import APIRoute
|
||||
@ -21,10 +20,6 @@ from user_agents import parse
|
||||
from application.settings import OPERATION_RECORD_METHOD, MONGO_DB_ENABLE, IGNORE_OPERATION_FUNCTION,\
|
||||
DEMO_WHITE_LIST_PATH, DEMO
|
||||
from core.mongo import get_database
|
||||
|
||||
|
||||
# 记录请求日志
|
||||
from utils import status
|
||||
from utils.response import ErrorResponse
|
||||
|
||||
|
||||
@ -137,3 +132,18 @@ def register_demo_env_middleware(app: FastAPI):
|
||||
if DEMO and request.method != "GET" and path not in DEMO_WHITE_LIST_PATH:
|
||||
return ErrorResponse(msg="演示环境,禁止操作")
|
||||
return await call_next(request)
|
||||
|
||||
|
||||
def register_jwt_refresh_middleware(app: FastAPI):
|
||||
"""
|
||||
JWT刷新中间件
|
||||
:param app:
|
||||
:return:
|
||||
"""
|
||||
|
||||
@app.middleware("http")
|
||||
async def jwt_refresh_middleware(request: Request, call_next):
|
||||
response = await call_next(request)
|
||||
refresh = request.scope.get('refresh', 0)
|
||||
response.headers["refresh"] = str(refresh)
|
||||
return response
|
||||
|
@ -29,7 +29,7 @@ cryptography==38.0.3
|
||||
dnspython==2.2.1
|
||||
ecdsa==0.18.0
|
||||
et-xmlfile==1.1.0
|
||||
fastapi==0.94.1
|
||||
fastapi==0.95.0
|
||||
frozenlist==1.3.3
|
||||
greenlet==2.0.1
|
||||
gunicorn==20.1.0
|
||||
|
@ -42,7 +42,7 @@ http.interceptors.response.use(
|
||||
// 获取错误信息
|
||||
const msg = res.data.message || errorCode[code] || errorCode['default']
|
||||
// 是否刷新token
|
||||
const refresh = res.data.refresh || false
|
||||
const refresh = res.header.refresh
|
||||
if (code === 500) {
|
||||
toast(msg)
|
||||
return Promise.reject(new Error(msg))
|
||||
@ -58,7 +58,7 @@ http.interceptors.response.use(
|
||||
toast(msg)
|
||||
return Promise.reject('error')
|
||||
} else if (code === 200) {
|
||||
if (refresh) {
|
||||
if (refresh === '1') {
|
||||
// 因token快过期,刷新token
|
||||
refreshToken().then((res) => {
|
||||
setToken(`${res.data.token_type} ${res.data.access_token}`)
|
||||
|
Loading…
x
Reference in New Issue
Block a user