From 98f53cbaaa2af685466846ed515c0bd2e629ed6c Mon Sep 17 00:00:00 2001 From: jayhgq Date: Fri, 27 Feb 2026 17:56:54 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4auth/app.py=EF=BC=9B=E6=9B=B4?= =?UTF-8?q?=E6=96=B0requirements.txt=E6=B7=BB=E5=8A=A0=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/auth/config.py | 58 ++++++++++++++++++++++++++++ backend/auth/{app.py => main.py} | 0 backend/auth/models.py | 36 +++++++++++++++++ backend/auth/requirements.txt | 5 +++ backend/auth/schemas.py | 66 ++++++++++++++++++++++++++++++++ 5 files changed, 165 insertions(+) create mode 100644 backend/auth/config.py rename backend/auth/{app.py => main.py} (100%) create mode 100644 backend/auth/models.py create mode 100644 backend/auth/schemas.py diff --git a/backend/auth/config.py b/backend/auth/config.py new file mode 100644 index 0000000..af82299 --- /dev/null +++ b/backend/auth/config.py @@ -0,0 +1,58 @@ +from pydantic_settings import BaseSettings +from typing import Optional + + +class PostgreSQLSettings(BaseSettings): + """PostgreSQL数据库配置""" + host: str = "localhost" + port: int = 5432 + user: str = "postgres" + password: str = "postgres" + database: str = "book_system" + min_size: int = 5 + max_size: int = 20 + + @property + def url(self) -> str: + """生成数据库连接URL""" + return f"postgresql+asyncpg://{self.user}:{self.password}@{self.host}:{self.port}/{self.database}" + + class Config: + env_prefix = "POSTGRES_" + + +class RedisSettings(BaseSettings): + """Redis配置""" + host: str = "localhost" + port: int = 6379 + password: Optional[str] = None + db: int = 0 + + @property + def url(self) -> str: + """生成Redis连接URL""" + if self.password: + return f"redis://:{self.password}@{self.host}:{self.port}/{self.db}" + return f"redis://{self.host}:{self.port}/{self.db}" + + class Config: + env_prefix = "REDIS_" + + +class AppSettings(BaseSettings): + """应用配置""" + name: str = "Book System API" + version: str = "1.0.0" + debug: bool = False + secret_key: str = "your-secret-key" + algorithm: str = "HS256" + access_token_expire_minutes: int = 30 + + class Config: + env_prefix = "APP_" + + +# 创建设置实例 +postgres_settings = PostgreSQLSettings() +redis_settings = RedisSettings() +app_settings = AppSettings() \ No newline at end of file diff --git a/backend/auth/app.py b/backend/auth/main.py similarity index 100% rename from backend/auth/app.py rename to backend/auth/main.py diff --git a/backend/auth/models.py b/backend/auth/models.py new file mode 100644 index 0000000..eda56bd --- /dev/null +++ b/backend/auth/models.py @@ -0,0 +1,36 @@ +from sqlalchemy import Column, Integer, String, DateTime, ForeignKey +from sqlalchemy.orm import relationship +from sqlalchemy.ext.declarative import declarative_base +from datetime import datetime + +Base = declarative_base() + + +class Role(Base): + """角色数据库模型""" + __tablename__ = "role" + id = Column(Integer, primary_key=True, index=True, comment="角色ID") + name = Column(String(50), nullable=False, unique=True, comment="角色名称") + createtime = Column(DateTime, default=datetime.utcnow, comment="创建时间") + creator = Column(String(50), nullable=True, comment="创建人") + + # 关联到User + users = relationship("User", back_populates="role_rel") + + +class User(Base): + """用户数据库模型""" + __tablename__ = "users" + id = Column(Integer, primary_key=True, index=True) + username = Column(String(50), unique=True, nullable=False, comment="登录名") + nickname = Column(String(50), nullable=False, comment="昵称") + email = Column(String(50), nullable=True, comment="电子邮箱") + phone = Column(String(11), nullable=True, comment="手机号码") + wx_openid = Column(String(100), nullable=True, comment="微信OpenID") + password = Column(String(100), nullable=False, comment="密码") + role_id = Column(Integer, ForeignKey("role.id"), default=2, comment="角色ID") + createtime = Column(DateTime, default=datetime.utcnow, comment="创建时间") + lastlogintime = Column(DateTime, nullable=True, comment="最后登录时间") + + # 关联到Role + role_rel = relationship("Role", back_populates="users") \ No newline at end of file diff --git a/backend/auth/requirements.txt b/backend/auth/requirements.txt index 886b969..98e345d 100644 --- a/backend/auth/requirements.txt +++ b/backend/auth/requirements.txt @@ -2,9 +2,14 @@ fastapi>=0.133.0 uvicorn[standard]>=0.41.0 +# Pydantic数据验证 +pydantic>=2.5.0 +pydantic-settings>=2.1.0 + # PostgreSQL + SQLAlchemy ORM(包含异步支持) sqlalchemy>=2.0.46 asyncpg>=0.31.0 +alembic>=1.18.4 # Redis异步客户端 redis>=7.2.0 \ No newline at end of file diff --git a/backend/auth/schemas.py b/backend/auth/schemas.py new file mode 100644 index 0000000..14d0638 --- /dev/null +++ b/backend/auth/schemas.py @@ -0,0 +1,66 @@ +from pydantic import BaseModel, EmailStr, Field +from typing import Optional +from datetime import datetime + + +class UserBase(BaseModel): + """用户基础模型""" + username: str = Field(..., min_length=3, max_length=50, description="登录名") + nickname: str = Field(..., max_length=50, description="昵称") + email: Optional[EmailStr] = Field(None, max_length=50, description="电子邮箱") + phone: Optional[str] = Field(None, max_length=11, description="手机号码") + wx_openid: Optional[str] = Field(None, max_length=100, description="微信OpenID") + role_id: int = Field(2, description="角色ID") + + +class UserCreate(UserBase): + """用户创建模型""" + password: str = Field(..., min_length=6, max_length=50, description="密码") + + +class UserLogin(BaseModel): + """用户登录模型""" + username: str = Field(..., description="登录名") + password: str = Field(..., description="密码") + + +class UserResponse(UserBase): + """用户响应模型""" + id: int = Field(..., description="用户ID") + createtime: datetime = Field(..., description="创建时间") + lastlogintime: datetime = Field(..., description="最后登录时间") + + class Config: + from_attributes = True + + +class Token(BaseModel): + """令牌模型""" + access_token: str = Field(..., description="访问令牌") + token_type: str = Field(..., description="令牌类型") + + +class TokenData(BaseModel): + """令牌数据模型""" + user_id: Optional[int] = None + email: Optional[EmailStr] = None + + +class RoleBase(BaseModel): + """角色基础模型""" + name: str = Field(..., max_length=50, description="角色名称") + + +class RoleCreate(RoleBase): + """角色创建模型""" + creator: Optional[str] = Field(None, max_length=50, description="创建人") + + +class RoleResponse(RoleBase): + """角色响应模型""" + id: int = Field(..., description="角色ID") + createtime: datetime = Field(..., description="创建时间") + creator: Optional[str] = Field(None, description="创建人") + + class Config: + from_attributes = True \ No newline at end of file