mirror of
https://github.com/fastapi-practices/fastapi-best-architecture.git
synced 2026-09-21 21:15:13 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48574fb50a | ||
|
|
ee7fe3087d | ||
|
|
270ac3d941 | ||
|
|
2f76988076 | ||
|
|
b275481742 | ||
|
|
f3f1ceb595 |
@@ -1,3 +1,24 @@
|
|||||||
|
<a id="v1.4.0"></a>
|
||||||
|
# [v1.4.0](https://github.com/fastapi-practices/fastapi_best_architecture/releases/tag/v1.4.0) - 2025-05-22
|
||||||
|
|
||||||
|
## What's Changed
|
||||||
|
* Update changelog for v1.3.0 by [@wu-clan](https://github.com/wu-clan) in [#605](https://github.com/fastapi-practices/fastapi_best_architecture/pull/605)
|
||||||
|
* Add new plugin status check interface by [@wu-clan](https://github.com/wu-clan) in [#606](https://github.com/fastapi-practices/fastapi_best_architecture/pull/606)
|
||||||
|
* Update the new plugin status to changed by [@wu-clan](https://github.com/wu-clan) in [#607](https://github.com/fastapi-practices/fastapi_best_architecture/pull/607)
|
||||||
|
* Fix the task result schema param type by [@wu-clan](https://github.com/wu-clan) in [#611](https://github.com/fastapi-practices/fastapi_best_architecture/pull/611)
|
||||||
|
* Fix the plugin status update logic by [@wu-clan](https://github.com/wu-clan) in [#613](https://github.com/fastapi-practices/fastapi_best_architecture/pull/613)
|
||||||
|
* Update uninstall and build plugin api method by [@wu-clan](https://github.com/wu-clan) in [#614](https://github.com/fastapi-practices/fastapi_best_architecture/pull/614)
|
||||||
|
* Fix non-asyncio nested async IO by [@wu-clan](https://github.com/wu-clan) in [#610](https://github.com/fastapi-practices/fastapi_best_architecture/pull/610)
|
||||||
|
* Update the build plugin api params by [@wu-clan](https://github.com/wu-clan) in [#615](https://github.com/fastapi-practices/fastapi_best_architecture/pull/615)
|
||||||
|
* Update uv installation in docker deploy by [@wu-clan](https://github.com/wu-clan) in [#619](https://github.com/fastapi-practices/fastapi_best_architecture/pull/619)
|
||||||
|
* Update the OAuth2 module to plugin by [@wu-clan](https://github.com/wu-clan) in [#620](https://github.com/fastapi-practices/fastapi_best_architecture/pull/620)
|
||||||
|
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.3.0...v1.4.0
|
||||||
|
|
||||||
|
[Changes][v1.4.0]
|
||||||
|
|
||||||
|
|
||||||
<a id="v1.3.0"></a>
|
<a id="v1.3.0"></a>
|
||||||
# [v1.3.0](https://github.com/fastapi-practices/fastapi_best_architecture/releases/tag/v1.3.0) - 2025-05-16
|
# [v1.3.0](https://github.com/fastapi-practices/fastapi_best_architecture/releases/tag/v1.3.0) - 2025-05-16
|
||||||
|
|
||||||
@@ -511,6 +532,7 @@
|
|||||||
[Changes][v1.0.0]
|
[Changes][v1.0.0]
|
||||||
|
|
||||||
|
|
||||||
|
[v1.4.0]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.3.0...v1.4.0
|
||||||
[v1.3.0]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.2.0...v1.3.0
|
[v1.3.0]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.2.0...v1.3.0
|
||||||
[v1.2.0]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.1.2...v1.2.0
|
[v1.2.0]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.1.2...v1.2.0
|
||||||
[v1.1.2]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.1.1...v1.1.2
|
[v1.1.2]: https://github.com/fastapi-practices/fastapi_best_architecture/compare/v1.1.1...v1.1.2
|
||||||
|
|||||||
@@ -4,11 +4,9 @@
|
|||||||
|
|
||||||
# FastAPI Best Architecture
|
# FastAPI Best Architecture
|
||||||
|
|
||||||
English | [简体中文](./README.zh-CN.md)
|
|
||||||
|
|
||||||
Enterprise-level backend architecture solution
|
Enterprise-level backend architecture solution
|
||||||
|
|
||||||
**🔥Continuously updated and maintained🔥**
|
English | [简体中文](./README.zh-CN.md)
|
||||||
|
|
||||||
[](https://github.com/fastapi-practices/fastapi_best_architecture/blob/master/LICENSE)
|
[](https://github.com/fastapi-practices/fastapi_best_architecture/blob/master/LICENSE)
|
||||||
[](https://www.python.org/downloads/)
|
[](https://www.python.org/downloads/)
|
||||||
@@ -21,12 +19,10 @@ Enterprise-level backend architecture solution
|
|||||||

|

|
||||||
[](https://discord.com/invite/yNN3wTbVAC)
|
[](https://discord.com/invite/yNN3wTbVAC)
|
||||||

|

|
||||||
|
[](https://deepwiki.com/fastapi-practices/fastapi_best_architecture)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> This repository as a template library open to any person or enterprise can be used for free!
|
|
||||||
|
|
||||||
## Pseudo 3-tier architecture
|
## Pseudo 3-tier architecture
|
||||||
|
|
||||||
The mvc architecture is a common design pattern in python web, but the 3-tier architecture is even more fascinating
|
The mvc architecture is a common design pattern in python web, but the 3-tier architecture is even more fascinating
|
||||||
@@ -45,43 +41,7 @@ pattern, use templates to transform it to your heart's content!
|
|||||||
| data access | dao / mapper | crud |
|
| data access | dao / mapper | crud |
|
||||||
| model | model / entity | model |
|
| model | model / entity | model |
|
||||||
|
|
||||||
## Features
|
## Help
|
||||||
|
|
||||||
- [x] Global FastAPI PEP 593 Annotated parameter style
|
|
||||||
- [x] Comprehensive async/await + asgiref asynchronous design
|
|
||||||
- [x] Adheres to RESTful API specifications
|
|
||||||
- [x] Uses SQLAlchemy 2.0 with new syntax
|
|
||||||
- [x] Uses Pydantic v2 version
|
|
||||||
- [x] Implements role-menu RBAC access control
|
|
||||||
- [x] Integrates Casbin RBAC access control
|
|
||||||
- [x] Supports Celery asynchronous tasks
|
|
||||||
- [x] Custom-developed JWT authentication middleware
|
|
||||||
- [x] Supports global custom time zones
|
|
||||||
- [x] Supports Docker / Docker-compose deployment
|
|
||||||
- [x] Integrates Pytest unit testing
|
|
||||||
|
|
||||||
## Built-in Functions
|
|
||||||
|
|
||||||
- [x] User Management: Assign roles and permissions
|
|
||||||
- [x] Department Management: Configure organizational structure (company, department, team, etc.)
|
|
||||||
- [x] Menu Management: Set up menus and button-level permissions
|
|
||||||
- [x] Role Management: Configure roles, assign menus and permissions
|
|
||||||
- [x] Dictionary Management: Maintain common parameters and configurations
|
|
||||||
- [x] Parameter Management: Dynamically configure commonly used system parameters
|
|
||||||
- [x] Notification Announcements: Publish and maintain system notification and announcement information
|
|
||||||
- [x] Token Management: Detect online status, support forced logout
|
|
||||||
- [x] Multi-device Login: Support one-click switching between multi-device login modes
|
|
||||||
- [x] OAuth 2.0: Built-in custom-developed OAuth 2.0 authorization login
|
|
||||||
- [x] Plugin System: Hot-swappable plugin design to reduce coupling
|
|
||||||
- [x] Scheduled Tasks: Support scheduled, asynchronous tasks, and function calls
|
|
||||||
- [x] Code Generation: Automatically generate code with preview, write, and download support
|
|
||||||
- [x] Operation Logs: Record and query normal and abnormal operations
|
|
||||||
- [x] Login Logs: Record and query normal and abnormal logins
|
|
||||||
- [x] Cache Monitoring: Query system cache information and command statistics
|
|
||||||
- [x] Service Monitoring: View server hardware information and status
|
|
||||||
- [x] API Documentation: Automatically generate online interactive API documentation
|
|
||||||
|
|
||||||
## Development and deployment
|
|
||||||
|
|
||||||
For more details, please check
|
For more details, please check
|
||||||
the [official documentation](https://fastapi-practices.github.io/fastapi_best_architecture_docs/)
|
the [official documentation](https://fastapi-practices.github.io/fastapi_best_architecture_docs/)
|
||||||
|
|||||||
+3
-43
@@ -4,11 +4,9 @@
|
|||||||
|
|
||||||
# FastAPI Best Architecture
|
# FastAPI Best Architecture
|
||||||
|
|
||||||
简体中文 | [English](./README.md)
|
|
||||||
|
|
||||||
企业级后端架构解决方案
|
企业级后端架构解决方案
|
||||||
|
|
||||||
**🔥持续更新维护中🔥**
|
简体中文 | [English](./README.md)
|
||||||
|
|
||||||
[](https://github.com/fastapi-practices/fastapi_best_architecture/blob/master/LICENSE)
|
[](https://github.com/fastapi-practices/fastapi_best_architecture/blob/master/LICENSE)
|
||||||
[](https://www.python.org/downloads/)
|
[](https://www.python.org/downloads/)
|
||||||
@@ -21,12 +19,10 @@
|
|||||||

|

|
||||||
[](https://discord.com/invite/yNN3wTbVAC)
|
[](https://discord.com/invite/yNN3wTbVAC)
|
||||||

|

|
||||||
|
[](https://deepwiki.com/fastapi-practices/fastapi_best_architecture)
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> 此仓库作为模板库公开,任何人或企业均可免费使用!
|
|
||||||
|
|
||||||
## 伪三层架构
|
## 伪三层架构
|
||||||
|
|
||||||
mvc 架构作为常规设计模式,在 python web 中也很常见,但是三层架构更令人着迷
|
mvc 架构作为常规设计模式,在 python web 中也很常见,但是三层架构更令人着迷
|
||||||
@@ -43,43 +39,7 @@ mvc 架构作为常规设计模式,在 python web 中也很常见,但是三
|
|||||||
| 数据访问 | dao / mapper | crud |
|
| 数据访问 | dao / mapper | crud |
|
||||||
| 模型 | model / entity | model |
|
| 模型 | model / entity | model |
|
||||||
|
|
||||||
## 特性
|
## 帮助
|
||||||
|
|
||||||
- [x] 全局 FastAPI PEP 593 Annotated 参数风格
|
|
||||||
- [x] 全面 async/await + asgiref 异步设计
|
|
||||||
- [x] 遵循 RESTful API 规范
|
|
||||||
- [x] 使用 SQLAlchemy 2.0 全新语法
|
|
||||||
- [x] 使用 Pydantic v2 版本
|
|
||||||
- [x] 实现角色菜单 RBAC 访问控制
|
|
||||||
- [x] 集成 Casbin RBAC 访问控制
|
|
||||||
- [x] 支持 Celery 异步任务
|
|
||||||
- [x] 自研 JWT 认证中间件
|
|
||||||
- [x] 支持全局自定义时间时区
|
|
||||||
- [x] 支持 Docker / Docker-compose 部署
|
|
||||||
- [x] 集成 Pytest 单元测试
|
|
||||||
|
|
||||||
## 内置功能
|
|
||||||
|
|
||||||
- [x] 用户管理:分配角色和权限
|
|
||||||
- [x] 部门管理:配置组织架构(公司、部门、小组等)
|
|
||||||
- [x] 菜单管理:设置菜单及按钮级权限
|
|
||||||
- [x] 角色管理:配置角色、分配菜单和权限
|
|
||||||
- [x] 字典管理:维护常用参数和配置
|
|
||||||
- [x] 参数管理:系统常用参数动态配置
|
|
||||||
- [x] 通知公告:发布和维护系统通知公告信息
|
|
||||||
- [x] 令牌管理:检测在线状态,支持强制下线
|
|
||||||
- [x] 多端登录:支持一键切换多端登录模式
|
|
||||||
- [x] OAuth 2.0:内置自研 OAuth 2.0 授权登录
|
|
||||||
- [x] 插件系统:热插拔插件设计,降低耦合
|
|
||||||
- [x] 定时任务:支持定时,异步任务及函数调用
|
|
||||||
- [x] 代码生成:自动生成代码,支持预览、写入和下载
|
|
||||||
- [x] 操作日志:记录和查询正常和异常操作
|
|
||||||
- [x] 登录日志:记录和查询正常和异常登录
|
|
||||||
- [x] 缓存监控:查询系统缓存信息和命令统计
|
|
||||||
- [x] 服务监控:查看服务器硬件信息和状态
|
|
||||||
- [x] 接口文档:自动生成在线交互式 API 文档
|
|
||||||
|
|
||||||
## 开发部署
|
|
||||||
|
|
||||||
更多详情请查看 [官方文档](https://fastapi-practices.github.io/fastapi_best_architecture_docs/)
|
更多详情请查看 [官方文档](https://fastapi-practices.github.io/fastapi_best_architecture_docs/)
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ from backend.app.admin.schema.token import GetLoginToken, GetNewToken, GetSwagge
|
|||||||
from backend.app.admin.schema.user import AuthLoginParam
|
from backend.app.admin.schema.user import AuthLoginParam
|
||||||
from backend.app.admin.service.auth_service import auth_service
|
from backend.app.admin.service.auth_service import auth_service
|
||||||
from backend.common.response.response_schema import ResponseModel, ResponseSchemaModel, response_base
|
from backend.common.response.response_schema import ResponseModel, ResponseSchemaModel, response_base
|
||||||
from backend.common.security.jwt import DependsJwtAuth
|
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@@ -41,7 +40,7 @@ async def create_new_token(request: Request) -> ResponseSchemaModel[GetNewToken]
|
|||||||
return response_base.success(data=data)
|
return response_base.success(data=data)
|
||||||
|
|
||||||
|
|
||||||
@router.post('/logout', summary='用户登出', dependencies=[DependsJwtAuth])
|
@router.post('/logout', summary='用户登出')
|
||||||
async def user_logout(request: Request, response: Response) -> ResponseModel:
|
async def user_logout(request: Request, response: Response) -> ResponseModel:
|
||||||
await auth_service.logout(request=request, response=response)
|
await auth_service.logout(request=request, response=response)
|
||||||
return response_base.success()
|
return response_base.success()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
from backend.app.admin.api.v1.monitor.online import router as token_router
|
||||||
from backend.app.admin.api.v1.monitor.redis import router as redis_router
|
from backend.app.admin.api.v1.monitor.redis import router as redis_router
|
||||||
from backend.app.admin.api.v1.monitor.server import router as server_router
|
from backend.app.admin.api.v1.monitor.server import router as server_router
|
||||||
|
|
||||||
@@ -9,3 +10,4 @@ router = APIRouter(prefix='/monitors')
|
|||||||
|
|
||||||
router.include_router(redis_router, prefix='/redis', tags=['redis监控'])
|
router.include_router(redis_router, prefix='/redis', tags=['redis监控'])
|
||||||
router.include_router(server_router, prefix='/server', tags=['服务器监控'])
|
router.include_router(server_router, prefix='/server', tags=['服务器监控'])
|
||||||
|
router.include_router(token_router, prefix='/online', tags=['在线用户'])
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from typing import Annotated
|
|||||||
|
|
||||||
from fastapi import APIRouter, Depends, Path, Query, Request
|
from fastapi import APIRouter, Depends, Path, Query, Request
|
||||||
|
|
||||||
from backend.app.admin.schema.token import GetTokenDetail, KickOutToken
|
from backend.app.admin.schema.token import GetTokenDetail
|
||||||
from backend.common.enums import StatusType
|
from backend.common.enums import StatusType
|
||||||
from backend.common.response.response_schema import ResponseModel, ResponseSchemaModel, response_base
|
from backend.common.response.response_schema import ResponseModel, ResponseSchemaModel, response_base
|
||||||
from backend.common.security.jwt import DependsJwtAuth, jwt_decode, revoke_token, superuser_verify
|
from backend.common.security.jwt import DependsJwtAuth, jwt_decode, revoke_token, superuser_verify
|
||||||
@@ -18,8 +18,8 @@ from backend.database.redis import redis_client
|
|||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.get('', summary='获取令牌列表', dependencies=[DependsJwtAuth])
|
@router.get('', summary='获取在线用户', dependencies=[DependsJwtAuth])
|
||||||
async def get_tokens(
|
async def get_online(
|
||||||
username: Annotated[str | None, Query(description='用户名')] = None,
|
username: Annotated[str | None, Query(description='用户名')] = None,
|
||||||
) -> ResponseSchemaModel[list[GetTokenDetail]]:
|
) -> ResponseSchemaModel[list[GetTokenDetail]]:
|
||||||
token_keys = await redis_client.keys(f'{settings.TOKEN_REDIS_PREFIX}:*')
|
token_keys = await redis_client.keys(f'{settings.TOKEN_REDIS_PREFIX}:*')
|
||||||
@@ -82,8 +82,10 @@ async def get_tokens(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def kick_out(
|
async def kick_out(
|
||||||
request: Request, pk: Annotated[int, Path(description='用户 ID')], obj: KickOutToken
|
request: Request,
|
||||||
|
pk: Annotated[int, Path(description='用户 ID')],
|
||||||
|
session_uuid: Annotated[str, Query(description='会话 UUID')],
|
||||||
) -> ResponseModel:
|
) -> ResponseModel:
|
||||||
superuser_verify(request)
|
superuser_verify(request)
|
||||||
await revoke_token(str(pk), obj.session_uuid)
|
await revoke_token(str(pk), session_uuid)
|
||||||
return response_base.success()
|
return response_base.success()
|
||||||
@@ -8,7 +8,6 @@ from backend.app.admin.api.v1.sys.dept import router as dept_router
|
|||||||
from backend.app.admin.api.v1.sys.menu import router as menu_router
|
from backend.app.admin.api.v1.sys.menu import router as menu_router
|
||||||
from backend.app.admin.api.v1.sys.plugin import router as plugin_router
|
from backend.app.admin.api.v1.sys.plugin import router as plugin_router
|
||||||
from backend.app.admin.api.v1.sys.role import router as role_router
|
from backend.app.admin.api.v1.sys.role import router as role_router
|
||||||
from backend.app.admin.api.v1.sys.token import router as token_router
|
|
||||||
from backend.app.admin.api.v1.sys.upload import router as upload_router
|
from backend.app.admin.api.v1.sys.upload import router as upload_router
|
||||||
from backend.app.admin.api.v1.sys.user import router as user_router
|
from backend.app.admin.api.v1.sys.user import router as user_router
|
||||||
|
|
||||||
@@ -20,6 +19,5 @@ router.include_router(role_router, prefix='/roles', tags=['系统角色'])
|
|||||||
router.include_router(user_router, prefix='/users', tags=['系统用户'])
|
router.include_router(user_router, prefix='/users', tags=['系统用户'])
|
||||||
router.include_router(data_rule_router, prefix='/data-rules', tags=['系统数据规则'])
|
router.include_router(data_rule_router, prefix='/data-rules', tags=['系统数据规则'])
|
||||||
router.include_router(data_scope_router, prefix='/data-scopes', tags=['系统数据范围'])
|
router.include_router(data_scope_router, prefix='/data-scopes', tags=['系统数据范围'])
|
||||||
router.include_router(token_router, prefix='/tokens', tags=['系统令牌'])
|
|
||||||
router.include_router(upload_router, prefix='/upload', tags=['系统上传'])
|
router.include_router(upload_router, prefix='/upload', tags=['系统上传'])
|
||||||
router.include_router(plugin_router, prefix='/plugin', tags=['系统插件'])
|
router.include_router(plugin_router, prefix='/plugin', tags=['系统插件'])
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ class Menu(Base):
|
|||||||
id: Mapped[id_key] = mapped_column(init=False)
|
id: Mapped[id_key] = mapped_column(init=False)
|
||||||
title: Mapped[str] = mapped_column(String(50), comment='菜单标题')
|
title: Mapped[str] = mapped_column(String(50), comment='菜单标题')
|
||||||
name: Mapped[str] = mapped_column(String(50), comment='菜单名称')
|
name: Mapped[str] = mapped_column(String(50), comment='菜单名称')
|
||||||
path: Mapped[str] = mapped_column(String(200), comment='路由地址')
|
path: Mapped[str | None] = mapped_column(String(200), comment='路由地址')
|
||||||
sort: Mapped[int] = mapped_column(default=0, comment='排序')
|
sort: Mapped[int] = mapped_column(default=0, comment='排序')
|
||||||
icon: Mapped[str | None] = mapped_column(String(100), default=None, comment='菜单图标')
|
icon: Mapped[str | None] = mapped_column(String(100), default=None, comment='菜单图标')
|
||||||
type: Mapped[int] = mapped_column(default=0, comment='菜单类型(0目录 1菜单 2按钮)')
|
type: Mapped[int] = mapped_column(default=0, comment='菜单类型(0目录 1菜单 2按钮 3内嵌 4外链)')
|
||||||
component: Mapped[str | None] = mapped_column(String(255), default=None, comment='组件路径')
|
component: Mapped[str | None] = mapped_column(String(255), default=None, comment='组件路径')
|
||||||
perms: Mapped[str | None] = mapped_column(String(100), default=None, comment='权限标识')
|
perms: Mapped[str | None] = mapped_column(String(100), default=None, comment='权限标识')
|
||||||
status: Mapped[int] = mapped_column(default=1, comment='菜单状态(0停用 1正常)')
|
status: Mapped[int] = mapped_column(default=1, comment='菜单状态(0停用 1正常)')
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ class MenuSchemaBase(SchemaBase):
|
|||||||
|
|
||||||
title: str = Field(description='菜单标题')
|
title: str = Field(description='菜单标题')
|
||||||
name: str = Field(description='菜单名称')
|
name: str = Field(description='菜单名称')
|
||||||
path: str = Field(description='路由路径')
|
path: str | None = Field(None, description='路由地址')
|
||||||
parent_id: int | None = Field(None, description='菜单父级 ID')
|
parent_id: int | None = Field(None, description='菜单父级 ID')
|
||||||
sort: int = Field(0, ge=0, description='排序')
|
sort: int = Field(0, ge=0, description='排序')
|
||||||
icon: str | None = Field(None, description='图标')
|
icon: str | None = Field(None, description='图标')
|
||||||
type: MenuType = Field(MenuType.directory, description='菜单类型(0目录 1菜单 2按钮)')
|
type: MenuType = Field(MenuType.directory, description='菜单类型(0目录 1菜单 2按钮 3内嵌 4外链)')
|
||||||
component: str | None = Field(None, description='组件路径')
|
component: str | None = Field(None, description='组件路径')
|
||||||
perms: str | None = Field(None, description='权限标识')
|
perms: str | None = Field(None, description='权限标识')
|
||||||
status: StatusType = Field(StatusType.enable, description='状态')
|
status: StatusType = Field(StatusType.enable, description='状态')
|
||||||
|
|||||||
@@ -35,12 +35,6 @@ class GetLoginToken(AccessTokenBase):
|
|||||||
user: GetUserInfoDetail = Field(description='用户信息')
|
user: GetUserInfoDetail = Field(description='用户信息')
|
||||||
|
|
||||||
|
|
||||||
class KickOutToken(SchemaBase):
|
|
||||||
"""踢出令牌"""
|
|
||||||
|
|
||||||
session_uuid: str = Field(description='会话 UUID')
|
|
||||||
|
|
||||||
|
|
||||||
class GetTokenDetail(SchemaBase):
|
class GetTokenDetail(SchemaBase):
|
||||||
"""令牌详情"""
|
"""令牌详情"""
|
||||||
|
|
||||||
|
|||||||
@@ -211,11 +211,17 @@ class AuthService:
|
|||||||
:param response: FastAPI 响应对象
|
:param response: FastAPI 响应对象
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
token = get_token(request)
|
try:
|
||||||
token_payload = jwt_decode(token)
|
token = get_token(request)
|
||||||
user_id = token_payload.id
|
token_payload = jwt_decode(token)
|
||||||
refresh_token = request.cookies.get(settings.COOKIE_REFRESH_TOKEN_KEY)
|
user_id = token_payload.id
|
||||||
response.delete_cookie(settings.COOKIE_REFRESH_TOKEN_KEY)
|
refresh_token = request.cookies.get(settings.COOKIE_REFRESH_TOKEN_KEY)
|
||||||
|
except errors.TokenError:
|
||||||
|
return
|
||||||
|
finally:
|
||||||
|
response.delete_cookie(settings.COOKIE_REFRESH_TOKEN_KEY)
|
||||||
|
|
||||||
|
# 清理缓存
|
||||||
if request.user.is_multi_login:
|
if request.user.is_multi_login:
|
||||||
await redis_client.delete(f'{settings.TOKEN_REDIS_PREFIX}:{user_id}:{token_payload.session_uuid}')
|
await redis_client.delete(f'{settings.TOKEN_REDIS_PREFIX}:{user_id}:{token_payload.session_uuid}')
|
||||||
if refresh_token:
|
if refresh_token:
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ class MenuType(IntEnum):
|
|||||||
directory = 0
|
directory = 0
|
||||||
menu = 1
|
menu = 1
|
||||||
button = 2
|
button = 2
|
||||||
|
embedded = 3
|
||||||
|
link = 4
|
||||||
|
|
||||||
|
|
||||||
class RoleDataRuleOperatorType(IntEnum):
|
class RoleDataRuleOperatorType(IntEnum):
|
||||||
|
|||||||
@@ -2,27 +2,28 @@ insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, pa
|
|||||||
values (1, 'test', 0, null, null, null, 1, 0, null, '2023-06-26 17:13:45', null);
|
values (1, 'test', 0, null, null, null, 1, 0, null, '2023-06-26 17:13:45', null);
|
||||||
|
|
||||||
insert into fba.sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
insert into fba.sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
||||||
values (1, '测试', 'Test', 'test', 0, null, 0, null, null, 0, 0, 1, null, null, null, '2023-07-27 19:14:10', null),
|
values (1, '测试', 'Test', 'test', 0, null, 0, null, null, 0, 0, 0, null, null, null, '2023-07-27 19:14:10', null),
|
||||||
(2, '仪表盘', 'Dashboard', 'dashboard', 0, 'material-symbols:dashboard', 0, null, null, 1, 1, 1, null, null, null, '2023-07-27 19:15:45', null),
|
(2, '仪表盘', 'Dashboard', 'dashboard', 0, 'material-symbols:dashboard', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:15:45', null),
|
||||||
(3, '工作台', 'Workspace', 'workspace', 0, null, 1, '/dashboard/workspace/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
(3, '工作台', 'Workspace', 'workspace', 0, null, 1, '/dashboard/workspace/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
||||||
(4, '数据分析', 'Analytics', 'analytics', 0, null, 1, '/dashboard/analytics/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
(4, '数据分析', 'Analytics', 'analytics', 0, null, 1, '/dashboard/analytics/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
||||||
(5, '系统管理', 'System', 'system', 0, 'eos-icons:admin', 0, null, null, 1, 1, 1, null, null, null, '2023-07-27 19:23:00', null),
|
(5, '系统管理', 'System', 'system', 0, 'eos-icons:admin', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:23:00', null),
|
||||||
(6, '部门管理', 'SysDept', 'sys-dept', 0, null, 1, '/system/dept/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:23:42', null),
|
(6, '部门管理', 'SysDept', 'sys-dept', 0, null, 1, '/system/dept/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:23:42', null),
|
||||||
(7, '用户管理', 'SysUser', 'sys-user', 0, null, 1, '/system/user/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:13', null),
|
(7, '用户管理', 'SysUser', 'sys-user', 0, null, 1, '/system/user/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:13', null),
|
||||||
(8, '角色管理', 'SysRole', 'sys-role', 0, null, 1, '/system/role/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:45', null),
|
(8, '角色管理', 'SysRole', 'sys-role', 0, null, 1, '/system/role/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:45', null),
|
||||||
(9, '菜单管理', 'SysMenu', 'sys-menu', 0, null, 1, '/system/menu/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:45:29', null),
|
(9, '菜单管理', 'SysMenu', 'sys-menu', 0, null, 1, '/system/menu/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:45:29', null),
|
||||||
(10, '插件管理', 'SysPlugin', 'sys-plugin', 0, null, 1, '/system/plugin/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
(10, '插件管理', 'SysPlugin', 'sys-plugin', 0, null, 1, '/system/plugin/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
||||||
(11, '数据权限', 'SysDataPermission', 'sys-data-permission', 0, null, 1, '/system/data-permission/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
(11, '数据权限', 'SysDataPermission', 'sys-data-permission', 0, null, 1, '/system/data-permission/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
||||||
(12, '系统自动化', 'Automation', 'automation', 0, 'material-symbols:automation', 0, null, null, 1, 1, 1, null, null, null, '2024-07-27 02:06:20', null),
|
(12, '系统自动化', 'Automation', 'automation', 0, 'material-symbols:automation', 0, null, null, 1, 1, 0, null, null, null, '2024-07-27 02:06:20', null),
|
||||||
(13, '代码生成', 'CodeGenerator', 'code-generator', 0, null, 1, '/automation/code-generator/index.vue', null, 1, 1, 1, null, null, 12, '2024-07-27 12:24:54', null),
|
(13, '代码生成', 'CodeGenerator', 'code-generator', 0, null, 1, '/automation/code-generator/index.vue', null, 1, 1, 1, null, null, 12, '2024-07-27 12:24:54', null),
|
||||||
(14, '系统监控', 'Monitor', 'monitor', 0, 'mdi:monitor-eye', 0, null, null, 1, 1, 1, null, null, null, '2023-07-27 19:27:08', null),
|
(14, '系统监控', 'Monitor', 'monitor', 0, 'mdi:monitor-eye', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:27:08', null),
|
||||||
(15, 'Redis 监控', 'Redis', 'redis', 0, null, 1, '/monitor/redis/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:03', null),
|
(15, 'Redis 监控', 'Redis', 'redis', 0, null, 1, '/monitor/redis/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:03', null),
|
||||||
(16, '服务器监控', 'Server', 'server', 0, null, 1, '/monitor/server/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:29', null),
|
(16, '服务器监控', 'Server', 'server', 0, null, 1, '/monitor/server/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:29', null),
|
||||||
(17, '日志', 'Log', 'log', 0, 'carbon:cloud-logging', 0, null, null, 1, 1, 1, null, null, null, '2023-07-27 19:19:59', null),
|
(17, '日志', 'Log', 'log', 0, 'carbon:cloud-logging', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:19:59', null),
|
||||||
(18, '登录日志', 'Login', 'login', 0, null, 1, '/log/login/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:20:56', null),
|
(18, '登录日志', 'Login', 'login', 0, null, 1, '/log/login/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:20:56', null),
|
||||||
(19, '操作日志', 'Opera', 'opera', 0, null, 1, '/log/opera/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:21:28', null),
|
(19, '操作日志', 'Opera', 'opera', 0, null, 1, '/log/opera/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:21:28', null),
|
||||||
(20, '官网', 'Site', '', 998, 'dashicons:admin-site', 1, null, null, 1, 1, 1, 'https://fastapi-practices.github.io/fastapi_best_architecture_docs/', null, null, '2023-07-27 19:22:24', null),
|
(20, 'Apifox', 'Apifox', 'apifox', 997, 'simple-icons:apifox', 3, null, null, 1, 1, 0, 'https://apifox.com/apidoc/shared-28a93f02-730b-4f33-bb5e-4dad92058cc0', null, null, '2024-05-22 16:27:00', null),
|
||||||
(21, '赞助', 'Sponsor', '', 999, 'material-icon-theme:github-sponsors', 1, null, null, 1, 1, 1, 'https://wu-clan.github.io/sponsor/', null, null, '2024-07-27 12:39:57', null);
|
(21, '官网', 'Site', '', 998, 'dashicons:admin-site', 4, null, null, 1, 1, 0, 'https://fastapi-practices.github.io/fastapi_best_architecture_docs/', null, null, '2024-07-27 19:22:24', null),
|
||||||
|
(22, '赞助', 'Sponsor', '', 999, 'material-icon-theme:github-sponsors', 4, null, null, 1, 1, 0, 'https://wu-clan.github.io/sponsor/', null, null, '2024-07-27 12:39:57', null);
|
||||||
|
|
||||||
insert into sys_role (id, name, status, remark, created_time, updated_time)
|
insert into sys_role (id, name, status, remark, created_time, updated_time)
|
||||||
values (1, 'test', 1, null, '2023-06-26 17:13:45', null);
|
values (1, 'test', 1, null, '2023-06-26 17:13:45', null);
|
||||||
|
|||||||
@@ -2,27 +2,28 @@ insert into sys_dept (id, name, sort, leader, phone, email, status, del_flag, pa
|
|||||||
values (1, 'test', 0, null, null, null, 1, 0, null, '2023-06-26 17:13:45', null);
|
values (1, 'test', 0, null, null, null, 1, 0, null, '2023-06-26 17:13:45', null);
|
||||||
|
|
||||||
insert into fba.sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
insert into fba.sys_menu (id, title, name, path, sort, icon, type, component, perms, status, display, cache, link, remark, parent_id, created_time, updated_time)
|
||||||
values (1, '测试', 'Test', 'test', 0, null, 0, null, null, 0, 0, 1, null, null, null, '2023-07-27 19:14:10', null),
|
values (1, '测试', 'Test', 'test', 0, null, 0, null, null, 0, 0, 0, null, null, null, '2023-07-27 19:14:10', null),
|
||||||
(2, '仪表盘', 'Dashboard', 'dashboard', 0, 'material-symbols:dashboard', 0, null, null, 1, 1, 1, null, null, null, '2023-07-27 19:15:45', null),
|
(2, '仪表盘', 'Dashboard', 'dashboard', 0, 'material-symbols:dashboard', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:15:45', null),
|
||||||
(3, '工作台', 'Workspace', 'workspace', 0, null, 1, '/dashboard/workspace/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
(3, '工作台', 'Workspace', 'workspace', 0, null, 1, '/dashboard/workspace/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
||||||
(4, '数据分析', 'Analytics', 'analytics', 0, null, 1, '/dashboard/analytics/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
(4, '数据分析', 'Analytics', 'analytics', 0, null, 1, '/dashboard/analytics/index.vue', null, 1, 1, 1, null, null, 2, '2023-07-27 19:17:59', null),
|
||||||
(5, '系统管理', 'System', 'system', 0, 'eos-icons:admin', 0, null, null, 1, 1, 1, null, null, null, '2023-07-27 19:23:00', null),
|
(5, '系统管理', 'System', 'system', 0, 'eos-icons:admin', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:23:00', null),
|
||||||
(6, '部门管理', 'SysDept', 'sys-dept', 0, null, 1, '/system/dept/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:23:42', null),
|
(6, '部门管理', 'SysDept', 'sys-dept', 0, null, 1, '/system/dept/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:23:42', null),
|
||||||
(7, '用户管理', 'SysUser', 'sys-user', 0, null, 1, '/system/user/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:13', null),
|
(7, '用户管理', 'SysUser', 'sys-user', 0, null, 1, '/system/user/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:13', null),
|
||||||
(8, '角色管理', 'SysRole', 'sys-role', 0, null, 1, '/system/role/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:45', null),
|
(8, '角色管理', 'SysRole', 'sys-role', 0, null, 1, '/system/role/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:25:45', null),
|
||||||
(9, '菜单管理', 'SysMenu', 'sys-menu', 0, null, 1, '/system/menu/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:45:29', null),
|
(9, '菜单管理', 'SysMenu', 'sys-menu', 0, null, 1, '/system/menu/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:45:29', null),
|
||||||
(10, '插件管理', 'SysPlugin', 'sys-plugin', 0, null, 1, '/system/plugin/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
(10, '插件管理', 'SysPlugin', 'sys-plugin', 0, null, 1, '/system/plugin/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
||||||
(11, '数据权限', 'SysDataPermission', 'sys-data-permission', 0, null, 1, '/system/data-permission/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
(11, '数据权限', 'SysDataPermission', 'sys-data-permission', 0, null, 1, '/system/data-permission/index.vue', null, 1, 1, 1, null, null, 5, '2023-07-27 19:24:12', null),
|
||||||
(12, '系统自动化', 'Automation', 'automation', 0, 'material-symbols:automation', 0, null, null, 1, 1, 1, null, null, null, '2024-07-27 02:06:20', null),
|
(12, '系统自动化', 'Automation', 'automation', 0, 'material-symbols:automation', 0, null, null, 1, 1, 0, null, null, null, '2024-07-27 02:06:20', null),
|
||||||
(13, '代码生成', 'CodeGenerator', 'code-generator', 0, null, 1, '/automation/code-generator/index.vue', null, 1, 1, 1, null, null, 12, '2024-07-27 12:24:54', null),
|
(13, '代码生成', 'CodeGenerator', 'code-generator', 0, null, 1, '/automation/code-generator/index.vue', null, 1, 1, 1, null, null, 12, '2024-07-27 12:24:54', null),
|
||||||
(14, '系统监控', 'Monitor', 'monitor', 0, 'mdi:monitor-eye', 0, null, null, 1, 1, 1, null, null, null, '2023-07-27 19:27:08', null),
|
(14, '系统监控', 'Monitor', 'monitor', 0, 'mdi:monitor-eye', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:27:08', null),
|
||||||
(15, 'Redis 监控', 'Redis', 'redis', 0, null, 1, '/monitor/redis/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:03', null),
|
(15, 'Redis 监控', 'Redis', 'redis', 0, null, 1, '/monitor/redis/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:03', null),
|
||||||
(16, '服务器监控', 'Server', 'server', 0, null, 1, '/monitor/server/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:29', null),
|
(16, '服务器监控', 'Server', 'server', 0, null, 1, '/monitor/server/index.vue', null, 1, 1, 1, null, null, 14, '2023-07-27 19:28:29', null),
|
||||||
(17, '日志', 'Log', 'log', 0, 'carbon:cloud-logging', 0, null, null, 1, 1, 1, null, null, null, '2023-07-27 19:19:59', null),
|
(17, '日志', 'Log', 'log', 0, 'carbon:cloud-logging', 0, null, null, 1, 1, 0, null, null, null, '2023-07-27 19:19:59', null),
|
||||||
(18, '登录日志', 'Login', 'login', 0, null, 1, '/log/login/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:20:56', null),
|
(18, '登录日志', 'Login', 'login', 0, null, 1, '/log/login/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:20:56', null),
|
||||||
(19, '操作日志', 'Opera', 'opera', 0, null, 1, '/log/opera/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:21:28', null),
|
(19, '操作日志', 'Opera', 'opera', 0, null, 1, '/log/opera/index.vue', null, 1, 1, 1, null, null, 17, '2023-07-27 19:21:28', null),
|
||||||
(20, '官网', 'Site', '', 998, 'dashicons:admin-site', 1, null, null, 1, 1, 1, 'https://fastapi-practices.github.io/fastapi_best_architecture_docs/', null, null, '2023-07-27 19:22:24', null),
|
(20, 'Apifox', 'Apifox', 'apifox', 997, 'simple-icons:apifox', 3, null, null, 1, 1, 0, 'https://apifox.com/apidoc/shared-28a93f02-730b-4f33-bb5e-4dad92058cc0', null, null, '2024-05-22 16:27:00', null),
|
||||||
(21, '赞助', 'Sponsor', '', 999, 'material-icon-theme:github-sponsors', 1, null, null, 1, 1, 1, 'https://wu-clan.github.io/sponsor/', null, null, '2024-07-27 12:39:57', null);
|
(21, '官网', 'Site', '', 998, 'dashicons:admin-site', 4, null, null, 1, 1, 0, 'https://fastapi-practices.github.io/fastapi_best_architecture_docs/', null, null, '2024-07-27 19:22:24', null),
|
||||||
|
(22, '赞助', 'Sponsor', '', 999, 'material-icon-theme:github-sponsors', 4, null, null, 1, 1, 0, 'https://wu-clan.github.io/sponsor/', null, null, '2024-07-27 12:39:57', null);
|
||||||
|
|
||||||
insert into sys_role (id, name, status, remark, created_time, updated_time)
|
insert into sys_role (id, name, status, remark, created_time, updated_time)
|
||||||
values (1, 'test', 1, null, '2023-06-26 17:13:45', null);
|
values (1, 'test', 1, null, '2023-06-26 17:13:45', null);
|
||||||
|
|||||||
@@ -93,16 +93,16 @@ def get_vben5_tree_data(row: Sequence[RowData]) -> list[dict[str, Any]]:
|
|||||||
:param row: 原始数据行序列
|
:param row: 原始数据行序列
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# 需要移除的原始字段
|
meta_keys = {'title', 'icon', 'link', 'cache', 'display', 'status'}
|
||||||
remove_keys = {'title', 'icon', 'link', 'cache', 'display', 'status'}
|
|
||||||
|
|
||||||
vben5_nodes = [
|
vben5_nodes = [
|
||||||
{
|
{
|
||||||
**{k: v for k, v in node.items() if k not in remove_keys},
|
**{k: v for k, v in node.items() if k not in meta_keys},
|
||||||
'meta': {
|
'meta': {
|
||||||
'title': node['title'],
|
'title': node['title'],
|
||||||
'icon': node['icon'],
|
'icon': node['icon'],
|
||||||
'link': node['link'],
|
'iframeSrc': node['link'] if node['type'] == 3 else '',
|
||||||
|
'link': node['link'] if node['type'] == 4 else '',
|
||||||
'keepAlive': node['cache'],
|
'keepAlive': node['cache'],
|
||||||
'hideInMenu': not bool(node['display']),
|
'hideInMenu': not bool(node['display']),
|
||||||
'menuVisibleWithForbidden': not bool(node['status']),
|
'menuVisibleWithForbidden': not bool(node['status']),
|
||||||
|
|||||||
Reference in New Issue
Block a user