Compare commits

...

7 Commits

Author SHA1 Message Date
chenwj113 fc5d6b8953 fix: 更新Dockerfile文件
Gitea Action for docker build runtime / build-runtime (push) Successful in 5m53s Details
2024-09-02 10:11:46 +08:00
chenwj113 6d69a18b03 fix: 运行时环境替换为alpine
Gitea Action for docker build / build-app (push) Successful in 1m23s Details
Gitea Action for docker build runtime / build-runtime (push) Successful in 4m18s Details
2024-08-16 18:37:51 +08:00
chenwj113 61f91fa932 fix: 去除gitea action的pyproject.toml触发path
Gitea Action for docker build / build-app (push) Successful in 1m1s Details
2024-08-15 18:35:00 +08:00
chenweijia ee14c5591a bugfix: 修复gitea action构建脚本的bug
Gitea Action for docker build / build-app (push) Successful in 25s Details
Gitea Action for docker build runtime / build-runtime (push) Successful in 4m17s Details
2024-08-15 17:11:05 +08:00
chenweijia dce678ca95 fix: 更改gitea action获取版本号的方式
Gitea Action for docker build runtime / build-runtime (push) Successful in 4m27s Details
Gitea Action for docker build / build-app (push) Successful in 33s Details
2024-08-15 17:03:16 +08:00
chenweijia 8982dd82d8 fix: 添加用户验证功能
Gitea Action for docker build / build-app (push) Successful in 47s Details
Gitea Action for docker build runtime / build-runtime (push) Successful in 3m46s Details
2024-08-15 13:33:43 +08:00
chenweijia 8459e0c447 fix: 增加一个请求限制功能
Gitea Action for docker build / build-app (push) Successful in 34s Details
Gitea Action for docker build runtime / build-runtime (push) Successful in 5m20s Details
2024-08-14 14:20:19 +08:00
12 changed files with 583 additions and 103 deletions

View File

@ -5,9 +5,10 @@ on:
branches: [master]
paths-ignore:
- 'requirements.txt'
- 'RuntimeDockerfile'
- '*RuntimeDockerfile'
- '.gitignore'
- 'README.md'
- 'pyproject.toml'
- '.gitea/workflows/**'
@ -27,16 +28,8 @@ jobs:
- run: |
var=${{ gitea.repository }}
repo=${var##*/}
url="https://hub.airpig.cn/api/v2.0/projects/library/repositories/${repo}/artifacts?page=1&page_size=10&with_tag=true&with_label=false&with_scan_overview=false&with_signature=false&with_immutable_status=false&with_accessory=false"
version=$(curl -X 'GET' $url \
-H 'accept: application/json' \
-H 'X-Accept-Vulnerabilities: application/vnd.security.vulnerability.report; version=1.1, application/vnd.scanner.adapter.vuln.report.harbor+json; version=1.0' \
-u 'admin:Chenweijia!' | jq '.[0].tags[0].name')
if [ ! $version ]; then
new_version=v1.0.0
else
new_version=$(echo $version | sed 's/\"//g' | awk -F. '{$NF = $NF + 1;} 1' OFS=.)
fi
version=$(grep -oP '(?<=version = ")(.*)(?=")' "pyproject.toml")
new_version="v${version}"
docker build -t hub.airpig.cn/library/$repo:$new_version .
docker push hub.airpig.cn/library/$repo:$new_version
docker rmi hub.airpig.cn/library/$repo:$new_version

View File

@ -6,8 +6,7 @@ on:
paths:
- 'requirements.txt'
- 'poetry.lock'
- 'pyproject.toml'
- 'RuntimeDockerfile'
- '*RuntimeDockerfile'
jobs:
build-runtime:
@ -25,18 +24,9 @@ jobs:
- run: |
var=${{ gitea.repository }}
repo=${var##*/}"-runtime"
echo $repo
url="https://hub.airpig.cn/api/v2.0/projects/library/repositories/${repo}/artifacts?page=1&page_size=10&with_tag=true&with_label=false&with_scan_overview=false&with_signature=false&with_immutable_status=false&with_accessory=false"
version=$(curl -X 'GET' $url \
-H 'accept: application/json' \
-H 'X-Accept-Vulnerabilities: application/vnd.security.vulnerability.report; version=1.1, application/vnd.scanner.adapter.vuln.report.harbor+json; version=1.0' \
-u 'admin:Chenweijia!' | jq '.[0].tags[0].name')
if [ ! $version ]; then
new_version=v1.0.0
else
new_version=$(echo $version | sed 's/\"//g' | awk -F. '{$NF = $NF + 1;} 1' OFS=.)
fi
docker build -t hub.airpig.cn/library/$repo:$new_version -f RuntimeDockerfile .
version=$(grep -oP '(?<=version = ")(.*)(?=")' "pyproject.toml")
new_version="v${version}"
docker build -t hub.airpig.cn/library/$repo:$new_version -f AlpineRuntimeDockerfile .
docker push hub.airpig.cn/library/$repo:$new_version
docker rmi hub.airpig.cn/library/$repo:$new_version
- run: echo "This job's status is ${{ job.status }}."

30
AlpineRuntimeDockerfile Normal file
View File

@ -0,0 +1,30 @@
FROM python:3.11-alpine as builder
RUN pip install poetry -i https://mirrors.aliyun.com/pypi/simple/
WORKDIR /venv
COPY poetry.lock pyproject.toml /venv/
RUN poetry config virtualenvs.options.no-pip true \
&& poetry config virtualenvs.options.no-setuptools true \
&& poetry config virtualenvs.in-project true \
&& poetry install
FROM python:3.11-alpine as release
COPY --from=builder /venv /venv
ENV PATH="/venv/.venv/bin:${PATH}"
RUN chmod a+x /venv/.venv/bin/activate \
&& source /venv/.venv/bin/activate
WORKDIR /app
COPY . /app
ENV FAST_API_ENV=prod
CMD ["/usr/local/bin/uvicorn", "main:fast_api_app", "--reload", "--host", "0.0.0.0", "--port", "80"]

View File

@ -1,7 +1,7 @@
# FastAPI App 文档
## 0 开发说明
Python(3.8.6+) and pip(20.2.4+)
Python(3.10+) and pip(20.2.4+)
### 开发命名规范
> * 避免采用的名字
> 不要使用字符l小写字母elO大写字母ohI大写字母eye作为单字符变量名。
@ -32,12 +32,12 @@ database=test
## 2 开发环境下安装依赖和运行项目
``` bash
pip install poetry -i https://mirrors.aliyun.com/pypi/simple/ \
pip install poetry -i https://pypi.tuna.tsinghua.edu.cn/simple/ \
&& poetry source add --priority=primary mirrors https://pypi.tuna.tsinghua.edu.cn/simple/ \
&& poetry config virtualenvs.path /install \
&& poetry install
./start.bat (windows)
./start.sh (mac)
./start.sh (mac/linux)
```

47
main.py
View File

@ -1,27 +1,26 @@
import logging.config as logging_config
import os
from contextlib import asynccontextmanager
import fastapi_plugins
from fastapi import FastAPI, Request
from fastapi.exceptions import HTTPException, RequestValidationError
from fastapi.middleware.wsgi import WSGIMiddleware
# from fastapi.middleware.wsgi import WSGIMiddleware
from fastapi_sqlalchemy import DBSessionMiddleware
from authx.exceptions import AuthXException
from config import init_config
# from src.middleware.flask import flask_app
from src.utils.exception import (http_exception_handler,
request_validation_error_handler)
from src.utils.exception import http_exception_handler, request_validation_error_handler, authx_exception_handler
# 请求限制
import redis.asyncio as aio_redis
from fastapi_limiter import FastAPILimiter
def create_app():
app = FastAPI()
mysql_config, redis_config = init_config()
# 添加sqlalchemy数据库中间件
# once the middleware is applied, any route can then access the database session from the global ``db``
app.add_middleware(DBSessionMiddleware, db_url=mysql_config.sqlalchemy_db_uri)
@app.on_event("startup")
async def startup_event():
@asynccontextmanager
async def lifespan(app: FastAPI):
# 创建日志文件夹和临时文件上传文件夹
if not os.path.exists("files"):
os.mkdir("files")
@ -32,25 +31,33 @@ def create_app():
logging_config.fileConfig('conf/log.ini')
# 初始化配置文件
# Redis 缓存初始化
print(redis_config)
await fastapi_plugins.redis_plugin.init_app(app, redis_config)
await fastapi_plugins.redis_plugin.init()
@app.on_event("shutdown")
async def shutdown_event():
# 请求限制
await FastAPILimiter.init(redis=aio_redis.from_url("redis://localhost:6379", encoding="utf8"))
yield
# 应用关闭时关闭redis连接
await fastapi_plugins.redis_plugin.terminate()
await FastAPILimiter.close()
app = FastAPI(lifespan=lifespan)
# 添加sqlalchemy数据库中间件
# once the middleware is applied, any route can then access the database session from the global ``db``
app.add_middleware(DBSessionMiddleware, db_url=mysql_config.sqlalchemy_db_uri)
# 添加异常处理
app.add_exception_handler(HTTPException, http_exception_handler)
app.add_exception_handler(RequestValidationError, request_validation_error_handler)
# AuthX异常处理
app.add_exception_handler(AuthXException, authx_exception_handler)
# 可以在这里挂载Flask的应用复用之前项目的相关代码
# app.mount("/v1", WSGIMiddleware(flask_app))
# 在这里添加API route
from src.api import example
app.include_router(example.router, tags=["API示例"], prefix="/example")
# 在这里添加API route
from src.api import example,auth_example
app.include_router(example.router, tags=["API示例"], prefix="/v1/example")
app.include_router(auth_example.router, tags=["认证示例"], prefix="/v1/auth_example")
return app

361
poetry.lock generated
View File

@ -127,6 +127,31 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "authx"
version = "1.3.0"
description = "Ready to use and customizable Authentications and Oauth2 management for FastAPI"
optional = false
python-versions = ">=3.8"
files = [
{file = "authx-1.3.0-py3-none-any.whl", hash = "sha256:347485b78a5016e655ac78b0ff0dd0c2aef3935148af4a863145399a20c718e8"},
{file = "authx-1.3.0.tar.gz", hash = "sha256:1f7c102a74d082c6a8850c26ff1e8fba73a146589fd95d84531df41e091586a5"},
]
[package.dependencies]
fastapi = ">=0.111.0"
pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<3.0.0"
pydantic-settings = ">=2.1.0"
pyjwt = {version = ">=2.6.0,<3.0.0", extras = ["crypto"]}
python-dateutil = ">=2.8,<3.0.0"
python-jose = ">=3.3.0,<4.0.0"
pytz = ">=2023.3,<2025.0"
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "captcha"
version = "0.6.0"
@ -162,6 +187,90 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "cffi"
version = "1.17.0"
description = "Foreign Function Interface for Python calling C code."
optional = false
python-versions = ">=3.8"
files = [
{file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"},
{file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"},
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42"},
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d"},
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2"},
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab"},
{file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b"},
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206"},
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa"},
{file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f"},
{file = "cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc"},
{file = "cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2"},
{file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"},
{file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"},
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"},
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"},
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"},
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"},
{file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"},
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"},
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"},
{file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"},
{file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"},
{file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"},
{file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"},
{file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"},
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"},
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"},
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"},
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"},
{file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"},
{file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"},
{file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"},
{file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"},
{file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"},
{file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"},
{file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"},
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"},
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"},
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"},
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"},
{file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"},
{file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"},
{file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"},
{file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"},
{file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"},
{file = "cffi-1.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c"},
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e"},
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b"},
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e"},
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401"},
{file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c"},
{file = "cffi-1.17.0-cp38-cp38-win32.whl", hash = "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499"},
{file = "cffi-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c"},
{file = "cffi-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2"},
{file = "cffi-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759"},
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4"},
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82"},
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf"},
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058"},
{file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932"},
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693"},
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3"},
{file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4"},
{file = "cffi-1.17.0-cp39-cp39-win32.whl", hash = "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb"},
{file = "cffi-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29"},
{file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"},
]
[package.dependencies]
pycparser = "*"
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "charset-normalizer"
version = "3.3.2"
@ -301,6 +410,60 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "cryptography"
version = "43.0.0"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false
python-versions = ">=3.7"
files = [
{file = "cryptography-43.0.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74"},
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895"},
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22"},
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47"},
{file = "cryptography-43.0.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf"},
{file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55"},
{file = "cryptography-43.0.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431"},
{file = "cryptography-43.0.0-cp37-abi3-win32.whl", hash = "sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc"},
{file = "cryptography-43.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778"},
{file = "cryptography-43.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66"},
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5"},
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e"},
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5"},
{file = "cryptography-43.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f"},
{file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0"},
{file = "cryptography-43.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b"},
{file = "cryptography-43.0.0-cp39-abi3-win32.whl", hash = "sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf"},
{file = "cryptography-43.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709"},
{file = "cryptography-43.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c6d112bf61c5ef44042c253e4859b3cbbb50df2f78fa8fae6747a7814484a70"},
{file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:844b6d608374e7d08f4f6e6f9f7b951f9256db41421917dfb2d003dde4cd6b66"},
{file = "cryptography-43.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51956cf8730665e2bdf8ddb8da0056f699c1a5715648c1b0144670c1ba00b48f"},
{file = "cryptography-43.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:aae4d918f6b180a8ab8bf6511a419473d107df4dbb4225c7b48c5c9602c38c7f"},
{file = "cryptography-43.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:232ce02943a579095a339ac4b390fbbe97f5b5d5d107f8a08260ea2768be8cc2"},
{file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5bcb8a5620008a8034d39bce21dc3e23735dfdb6a33a06974739bfa04f853947"},
{file = "cryptography-43.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:08a24a7070b2b6804c1940ff0f910ff728932a9d0e80e7814234269f9d46d069"},
{file = "cryptography-43.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e9c5266c432a1e23738d178e51c2c7a5e2ddf790f248be939448c0ba2021f9d1"},
{file = "cryptography-43.0.0.tar.gz", hash = "sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e"},
]
[package.dependencies]
cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
[package.extras]
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"]
nox = ["nox"]
pep8test = ["check-sdist", "click", "mypy", "ruff"]
sdist = ["build"]
ssh = ["bcrypt (>=3.1.5)"]
test = ["certifi", "cryptography-vectors (==43.0.0)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
test-randomorder = ["pytest-randomly"]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "dnspython"
version = "2.6.1"
@ -326,6 +489,29 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "ecdsa"
version = "0.19.0"
description = "ECDSA cryptographic signature library (pure python)"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
files = [
{file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"},
{file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"},
]
[package.dependencies]
six = ">=1.9.0"
[package.extras]
gmpy = ["gmpy"]
gmpy2 = ["gmpy2"]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "email-validator"
version = "2.1.1"
@ -419,6 +605,26 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "fastapi-limiter"
version = "0.1.6"
description = "A request rate limiter for fastapi"
optional = false
python-versions = ">=3.9,<4.0"
files = [
{file = "fastapi_limiter-0.1.6-py3-none-any.whl", hash = "sha256:2e53179a4208b8f2c8795e38bb001324d3dc37d2800ff49fd28ec5caabf7a240"},
{file = "fastapi_limiter-0.1.6.tar.gz", hash = "sha256:6f5fde8efebe12eb33861bdffb91009f699369a3c2862cdc7c1d9acf912ff443"},
]
[package.dependencies]
fastapi = "*"
redis = ">=4.2.0rc1"
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "fastapi-plugins"
version = "0.13.0"
@ -809,6 +1015,22 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "itsdangerous"
version = "2.2.0"
description = "Safely pass data to untrusted environments and back."
optional = false
python-versions = ">=3.8"
files = [
{file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"},
{file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"},
]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "jinja2"
version = "3.1.4"
@ -1134,6 +1356,38 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "pyasn1"
version = "0.6.0"
description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)"
optional = false
python-versions = ">=3.8"
files = [
{file = "pyasn1-0.6.0-py2.py3-none-any.whl", hash = "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473"},
{file = "pyasn1-0.6.0.tar.gz", hash = "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c"},
]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "pycparser"
version = "2.22"
description = "C parser in Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "pydantic"
version = "2.7.3"
@ -1297,6 +1551,31 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "pyjwt"
version = "2.9.0"
description = "JSON Web Token implementation in Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"},
{file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"},
]
[package.dependencies]
cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""}
[package.extras]
crypto = ["cryptography (>=3.4.0)"]
dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"]
docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"]
tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "pymysql"
version = "1.1.1"
@ -1317,6 +1596,25 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "python-dateutil"
version = "2.9.0.post0"
description = "Extensions to the standard Python datetime module"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
files = [
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
]
[package.dependencies]
six = ">=1.5"
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "python-dotenv"
version = "1.0.1"
@ -1336,6 +1634,32 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "python-jose"
version = "3.3.0"
description = "JOSE implementation in Python"
optional = false
python-versions = "*"
files = [
{file = "python-jose-3.3.0.tar.gz", hash = "sha256:55779b5e6ad599c6336191246e95eb2293a9ddebd555f796a65f838f07e5d78a"},
{file = "python_jose-3.3.0-py2.py3-none-any.whl", hash = "sha256:9b1376b023f8b298536eedd47ae1089bcdb848f1535ab30555cd92002d78923a"},
]
[package.dependencies]
ecdsa = "!=0.15"
pyasn1 = "*"
rsa = "*"
[package.extras]
cryptography = ["cryptography (>=3.4.0)"]
pycrypto = ["pyasn1", "pycrypto (>=2.6.0,<2.7.0)"]
pycryptodome = ["pyasn1", "pycryptodome (>=3.3.1,<4.0.0)"]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "python-json-logger"
version = "2.0.7"
@ -1547,6 +1871,25 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "rsa"
version = "4.9"
description = "Pure-Python RSA implementation"
optional = false
python-versions = ">=3.6,<4"
files = [
{file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"},
{file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"},
]
[package.dependencies]
pyasn1 = ">=0.1.3"
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "shellingham"
version = "1.5.4"
@ -1563,6 +1906,22 @@ type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "six"
version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
[package.source]
type = "legacy"
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
reference = "mirrors"
[[package]]
name = "sniffio"
version = "1.3.1"
@ -2116,4 +2475,4 @@ reference = "mirrors"
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
content-hash = "39a4bc6981b275faba68cb572e406a60300d2d868e646fbbf62ad251e2288e37"
content-hash = "d43623d3a4da31efcc1a54e1318db9ef412e1791ae9af50374d0c5d6faae6357"

View File

@ -1,6 +1,6 @@
[tool.poetry]
name = "fastapi-app-template"
version = "0.1.0"
name = "fastapi-template"
version = "0.1.5"
description = ""
authors = ["chenwj113 <chenwj113@gmail.com>"]
license = "MIT"
@ -19,6 +19,9 @@ pytz = "^2024.1"
qiniu = "^7.13.2"
pillow = "^10.4.0"
captcha = "^0.6.0"
fastapi-limiter = "^0.1.6"
authx = "^1.3.0"
itsdangerous = "^2.2.0"
[[tool.poetry.source]]

View File

@ -1,25 +1,75 @@
aiofiles==22.1.0
aioredis==2.0.1
aiomysql==0.1.1
bcrypt==4.0.1
email_validator>=2.0.0
fastapi==0.111.0
fastapi-plugins==0.13.0
FastAPI-SQLAlchemy==0.2.1
pydantic>=2.0.0
pydantic-settings==2.2.1
# pydantic-sqlalchemy==0.0.9
python-multipart>=0.0.7
pytest==7.2.1
requests==2.28.2
sqlacodegen==2.3.0
SQLAlchemy==2.0.1
uvicorn==0.20.0
PyJWT==2.6.0
passlib==1.7.4
Pillow==9.4.0
captcha==0.4
jinja2==3.1.2
pycryptodome==3.17
qiniu==7.10.0
pytz==2022.7.1
--index-url https://pypi.tuna.tsinghua.edu.cn/simple
aiojobs==1.2.1 ; python_version >= "3.10" and python_version < "4.0"
aiomysql==0.1.1 ; python_version >= "3.10" and python_version < "4.0"
aioredis==2.0.1 ; python_version >= "3.10" and python_version < "4.0"
annotated-types==0.7.0 ; python_version >= "3.10" and python_version < "4.0"
anyio==4.4.0 ; python_version >= "3.10" and python_version < "4.0"
async-timeout==4.0.3 ; python_version >= "3.10" and python_version < "4.0"
authx==1.3.0 ; python_version >= "3.10" and python_version < "4.0"
captcha==0.6.0 ; python_version >= "3.10" and python_version < "4.0"
certifi==2024.6.2 ; python_version >= "3.10" and python_version < "4.0"
cffi==1.17.0 ; python_version >= "3.10" and python_version < "4.0" and platform_python_implementation != "PyPy"
charset-normalizer==3.3.2 ; python_version >= "3.10" and python_version < "4.0"
click==8.1.7 ; python_version >= "3.10" and python_version < "4.0"
colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and (sys_platform == "win32" or platform_system == "Windows")
cryptography==43.0.0 ; python_version >= "3.10" and python_version < "4.0"
dnspython==2.6.1 ; python_version >= "3.10" and python_version < "4.0"
ecdsa==0.19.0 ; python_version >= "3.10" and python_version < "4.0"
email-validator==2.1.1 ; python_version >= "3.10" and python_version < "4.0"
exceptiongroup==1.2.1 ; python_version >= "3.10" and python_version < "3.11"
fastapi-cli==0.0.4 ; python_version >= "3.10" and python_version < "4.0"
fastapi-limiter==0.1.6 ; python_version >= "3.10" and python_version < "4.0"
fastapi-plugins==0.13.0 ; python_version >= "3.10" and python_version < "4.0"
fastapi-sqlalchemy==0.2.1 ; python_version >= "3.10" and python_version < "4.0"
fastapi==0.111.0 ; python_version >= "3.10" and python_version < "4.0"
greenlet==3.0.3 ; python_version >= "3.10" and python_version < "4.0" and (platform_machine == "aarch64" or platform_machine == "ppc64le" or platform_machine == "x86_64" or platform_machine == "amd64" or platform_machine == "AMD64" or platform_machine == "win32" or platform_machine == "WIN32")
h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0"
hiredis==2.3.2 ; python_version >= "3.10" and python_version < "4.0"
httpcore==1.0.5 ; python_version >= "3.10" and python_version < "4.0"
httptools==0.6.1 ; python_version >= "3.10" and python_version < "4.0"
httpx==0.27.0 ; python_version >= "3.10" and python_version < "4.0"
idna==3.7 ; python_version >= "3.10" and python_version < "4.0"
itsdangerous==2.2.0 ; python_version >= "3.10" and python_version < "4.0"
jinja2==3.1.4 ; python_version >= "3.10" and python_version < "4.0"
markdown-it-py==3.0.0 ; python_version >= "3.10" and python_version < "4.0"
markupsafe==2.1.5 ; python_version >= "3.10" and python_version < "4.0"
mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0"
orjson==3.10.4 ; python_version >= "3.10" and python_version < "4.0"
passlib==1.7.4 ; python_version >= "3.10" and python_version < "4.0"
pillow==10.4.0 ; python_version >= "3.10" and python_version < "4.0"
pyasn1==0.6.0 ; python_version >= "3.10" and python_version < "4.0"
pycparser==2.22 ; python_version >= "3.10" and python_version < "4.0" and platform_python_implementation != "PyPy"
pydantic-core==2.18.4 ; python_version >= "3.10" and python_version < "4.0"
pydantic-settings==2.3.1 ; python_version >= "3.10" and python_version < "4.0"
pydantic==2.7.3 ; python_version >= "3.10" and python_version < "4.0"
pygments==2.18.0 ; python_version >= "3.10" and python_version < "4.0"
pyjwt[crypto]==2.9.0 ; python_version >= "3.10" and python_version < "4.0"
pymysql==1.1.1 ; python_version >= "3.10" and python_version < "4.0"
python-dateutil==2.9.0.post0 ; python_version >= "3.10" and python_version < "4.0"
python-dotenv==1.0.1 ; python_version >= "3.10" and python_version < "4.0"
python-jose==3.3.0 ; python_version >= "3.10" and python_version < "4.0"
python-json-logger==2.0.7 ; python_version >= "3.10" and python_version < "4.0"
python-multipart==0.0.9 ; python_version >= "3.10" and python_version < "4.0"
pytz==2024.1 ; python_version >= "3.10" and python_version < "4.0"
pyyaml==6.0.1 ; python_version >= "3.10" and python_version < "4.0"
qiniu==7.13.2 ; python_version >= "3.10" and python_version < "4.0"
redis==5.0.5 ; python_version >= "3.10" and python_version < "4.0"
redis[hiredis]==5.0.5 ; python_version >= "3.10" and python_version < "4.0"
requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0"
rich==13.7.1 ; python_version >= "3.10" and python_version < "4.0"
rsa==4.9 ; python_version >= "3.10" and python_version < "4"
shellingham==1.5.4 ; python_version >= "3.10" and python_version < "4.0"
six==1.16.0 ; python_version >= "3.10" and python_version < "4.0"
sniffio==1.3.1 ; python_version >= "3.10" and python_version < "4.0"
sqlalchemy==2.0.0 ; python_version >= "3.10" and python_version < "4.0"
starlette==0.37.2 ; python_version >= "3.10" and python_version < "4.0"
tenacity==8.3.0 ; python_version >= "3.10" and python_version < "4.0"
typer==0.12.3 ; python_version >= "3.10" and python_version < "4.0"
typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0"
ujson==5.10.0 ; python_version >= "3.10" and python_version < "4.0"
urllib3==2.2.2 ; python_version >= "3.10" and python_version < "4.0"
uvicorn[standard]==0.30.1 ; python_version >= "3.10" and python_version < "4.0"
uvloop==0.19.0 ; (sys_platform != "win32" and sys_platform != "cygwin") and platform_python_implementation != "PyPy" and python_version >= "3.10" and python_version < "4.0"
watchfiles==0.22.0 ; python_version >= "3.10" and python_version < "4.0"
websockets==12.0 ; python_version >= "3.10" and python_version < "4.0"

16
src/api/auth_example.py Normal file
View File

@ -0,0 +1,16 @@
from fastapi import APIRouter, HTTPException, Depends
# 校验授权token
from src.middleware.auth import security
router = APIRouter()
@router.get('/', dependencies=[Depends(security.access_token_required)])
def index():
return {"message": "Hello World"}
@router.get('/login')
def login(username: str, password: str):
if username == "test" and password == "test":
token = security.create_access_token(uid=username)
return {"access_token": token}
raise HTTPException(401, detail={"message": "Bad credentials"})

View File

@ -7,6 +7,8 @@ from fastapi.security import OAuth2PasswordBearer
from fastapi_plugins import depends_redis
from fastapi_sqlalchemy import db
from sqlalchemy.sql import text
from fastapi_limiter.depends import RateLimiter
from pydantic import BaseModel
from src.service.example import get_user_by_id
@ -15,8 +17,8 @@ from src.dtos.example import UserExampleListPagesResult
router = APIRouter()
@router.get("/")
# 并发数限制 每5秒最多100次请求
@router.get("/", dependencies=[Depends(RateLimiter(times=100, seconds=5))])
def index():
return {"msg": "This is Index Page"}

13
src/middleware/auth.py Normal file
View File

@ -0,0 +1,13 @@
from authx import AuthX, AuthXConfig
from datetime import timedelta
config = AuthXConfig()
config.JWT_ALGORITHM = "HS256"
config.JWT_SECRET_KEY = "SECRET_KEY"
config.JWT_TOKEN_LOCATION = ["headers", "query", "cookies", "json"]
config.JWT_HEADER_NAME = "X-Token"
config.JWT_HEADER_TYPE = ""
# access token expires in 24 hours
config.JWT_ACCESS_TOKEN_EXPIRES = timedelta(hours=24)
security = AuthX(config=config)

View File

@ -1,9 +1,10 @@
import logging
from collections import defaultdict
from fastapi import Request, status
from fastapi.exceptions import HTTPException, RequestValidationError
from fastapi.responses import JSONResponse
import authx.exceptions as authx_exceptions
from src.dtos import BaseResponse, ErrorModel
logger = logging.getLogger("uvicorn.error")
@ -11,35 +12,32 @@ logger = logging.getLogger("uvicorn.error")
def request_validation_error_handler(req: Request, exc: RequestValidationError):
"""
请求响应校验错误处理
请求校验错误处理
:param req:
:param exc:
:return:
"""
errors = exc.errors()
logger.error(f"{req.method} {req.url} , errors: {errors}")
response_errors = [error for error in errors if error["loc"][0] == "response"]
if len(response_errors) > 0:
message = "接口响应异常 "
else:
message = "接口请求异常 "
json_err = [err["msg"] for err in errors if "value_error.jsondecode" == err["type"]]
if json_err:
message += "请求参数JSON编码有误;"
value_err = [err["msg"] for err in errors if "value_error" == err["type"]]
if value_err:
message += "; ".join(value_err)
missing_err = [err["loc"][-1] for err in errors if "value_error.missing" == err["type"]]
if missing_err:
message += "缺少字段:{} ".format(", ".join(missing_err))
type_err = [err["msg"].replace("value", f"{err['loc'][1]}") for err in errors if "type_error" == err["type"]]
if type_err:
message += "; ".join(type_err)
not_none_err = [err["loc"][-1] for err in errors if "type_error.none.not_allowed" == err["type"]]
if not_none_err:
message += "字段:{} 不能为空".format(", ".join(not_none_err))
err_model = ErrorModel(code=status.HTTP_400_BAD_REQUEST, message=message, details=message)
group_err = defaultdict(list)
for err in errors:
group_err[err["type"]].append(err)
details = ""
for err_type, err_list in group_err.items():
match err_type:
case "missing" | "value_error.missing" :
details += f"缺少字段:{', '.join([err['loc'][-1] for err in err_list])};"
case "value_error.jsondecode":
details += "请求参数JSON编码有误;"
case "value_error":
details += "; ".join([err["msg"] for err in err_list])
case "type_error":
details += "; ".join([err["msg"].replace("value", f"{err['loc'][1]}") for err in err_list])
case "type_error.none.not_allowed":
details += f"字段:{', '.join([err['loc'][-1] for err in err_list])} 不能为空;"
case _:
pass
err_model = ErrorModel(code=status.HTTP_400_BAD_REQUEST, message="接口请求校验异常", details=details)
res = BaseResponse(error=err_model)
return JSONResponse(status_code=200, content=res.dict())
@ -54,4 +52,23 @@ def http_exception_handler(req: Request, exc: HTTPException):
logger.error(f"{req.method} {req.url} , exception:{exc.detail}")
err = ErrorModel(code=exc.status_code, message=exc.detail)
res = BaseResponse(result=None, error=err)
return JSONResponse(status_code=exc.status_code, content=res.dict())
return JSONResponse(status_code=exc.status_code, content=res.model_dump())
def authx_exception_handler(req: Request, exc: authx_exceptions.AuthXException):
"""
AuthX Exception 错误处理
:param req:
:param exc:
:return:
"""
logger.error(f"{req.method} {req.url} , exception:{exc}")
match type(exc):
case authx_exceptions.MissingTokenError:
err = ErrorModel(code=status.HTTP_401_UNAUTHORIZED, message="请求头缺失X-Token")
case authx_exceptions.JWTDecodeError:
err = ErrorModel(code=status.HTTP_401_UNAUTHORIZED, message="X-Token解析失败")
case _:
err = ErrorModel(code=status.HTTP_401_UNAUTHORIZED, message="未知的错误导致认证失败")
res = BaseResponse(result=None, error=err)
return JSONResponse(status_code=err.code, content=res.model_dump())