Files
fastapi_server/README.md

146 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# py_server
这是一个 FastAPI 异步 API 项目骨架,分层方式参考了 Hyperf 项目里的 `server/app`
## 分层对应
| Hyperf | FastAPI 当前项目 | 作用 |
| --- | --- | --- |
| `Controller/Admin` | `app/controller/admin` | 接收请求,调用 service |
| `Service/Admin` | `app/service/admin` | 业务逻辑 |
| `Common/Repository` | `app/common/repository` | 数据访问 |
| `Model` | `app/model` | 数据模型 |
| `Middleware/Admin` | `app/middleware/admin` | admin token 和权限校验 |
| `Lib/Jwt` | `app/lib/jwt` | JWT 签发、解析、黑名单 |
| `Request/Admin` | `app/request/admin` | 请求参数校验 |
| `Constants` | `app/constants` | 状态码和业务常量 |
| `Lib/Return` | `app/lib/response` | 统一返回结构 |
> Python 里 `return` 是关键字,所以参考 Hyperf 的 `Lib/Return` 在这里命名为 `lib/response`。
## 启动
```bash
.venv/bin/uvicorn app.main:app --reload
```
默认启动时会自动创建 SQLite 开发库,并创建一个 admin 用户:
- username: `admin`
- password: `admin`
本地配置可以复制:
```bash
cp .env.example .env
```
## Admin 登录接口
### 登录
```http
POST /admin/login/login
Content-Type: application/json
{
"username": "admin",
"password": "admin"
}
```
返回:
```json
{
"code": 0,
"message": "success",
"data": {
"access_token": "...",
"refresh_token": "...",
"expire_at": 3600
}
}
```
### 刷新 token
```http
POST /admin/login/refresh
Authorization: Bearer <refresh_token>
```
刷新成功后会签发新的 `access_token``refresh_token`,并把旧的 `refresh_token` 加入黑名单,防止重复刷新。
### 当前 admin 用户
```http
GET /admin/profile/current
Authorization: Bearer <access_token>
```
## JWT 逻辑
当前实现和参考 Hyperf 项目保持同样思路:
1. 登录成功后同时签发 `access_token``refresh_token`
2. 普通 admin 接口只接受 `access_token`
3. `/admin/login/refresh` 只接受 `refresh_token`
4. refresh 成功后,把旧 refresh token 加入黑名单。
5. token 会校验签名、过期时间、issuer 和 token 类型。
token 读取顺序和 Hyperf 中间件一致:
1. `Authorization: Bearer <token>`
2. `token` header
3. query string: `?token=...`
## FastAPI 依赖注入
Controller 里这段:
```python
service: LoginService = Depends(get_login_service)
```
可以理解为 FastAPI 版的 Hyperf 容器注入。
请求进来时FastAPI 会先调用 `get_login_service()`,把创建好的 `LoginService` 传给 `service` 参数。
`get_login_service()` 内部会继续组装:
- `AdminUserRepository`
- `BaseTokenService`
- `AdminReturn`
所以 controller 只负责接收请求和调用 service。
## `@lru_cache` 的作用
`app/core/dependencies.py` 里的:
```python
@lru_cache
def get_database() -> Database:
return Database(get_settings().database_path)
```
表示第一次调用时创建对象,后面再次调用时直接复用第一次创建的对象。
在这个项目里,它的作用类似 Hyperf 容器里的共享服务/单例服务。比如 JWT 黑名单必须复用同一个对象,否则旧 refresh token 加入黑名单后,下一次请求就查不到了。
## 测试
```bash
.venv/bin/python -m compileall app tests
.venv/bin/python -m unittest tests.test_admin_login_flow
```
测试覆盖:
- admin 登录成功
- access token 访问当前用户成功
- refresh token 换新 token 成功
- 旧 refresh token 复用失败
- access token 调用 refresh 接口失败