在日常开发、测试和数据分析中,快速查看SQLite数据库的表结构、执行查询并保存常用SQL模板是常见需求。本文实现一个可运行的Python全栈Web应用:后端基于FastAPI提供RESTful API,使用SQLAlchemy定义数据模型,通过Passlib bcrypt加盐哈希存储密码,JWT Bearer Token实现接口鉴权;前端使用Vue 3 + Vite构建登录注册、数据库连接管理、SQL查询台等页面。整个项目前后端分离,所有查询严格限制为只读(仅允许SELECT、PRAGMA、EXPLAIN语句),避免误操作风险。
一、技术栈与项目结构
后端:FastAPI、SQLAlchemy、Pydantic、Uvicorn、Passlib、PyJWT
数据库:SQLite(系统业务库db_manager.db + 示例库demo_data.db)
前端:Vue 3、Vite、Fetch API
项目采用前后端分离架构,通过HTTP + JSON + Bearer Token通信。后端模块划分清晰:用户认证、连接管理、SQL模板、查询执行、审计统计。
二、数据库与数据模型设计
系统使用SQLAlchemy ORM定义以下核心表:
- users:用户表(id, username, email, hashed_password, created_at)
- db_connections:数据库连接表(id, name, db_type, database_path, owner_id)
- saved_queries:SQL模板表(id, title, sql_text, connection_id, owner_id)
- audit_logs:审计日志表(id, action, detail, owner_id, created_at)
其中db_connections和saved_queries通过owner_id关联到用户,确保数据隔离。模型文件backend/app/models.py中User定义如下:- class User(Base):
- __tablename__ = "users"
- id = Column(Integer, primary_key=True, index=True)
- username = Column(String(50), unique=True, index=True, nullable=False)
- email = Column(String(120), unique=True, index=True, nullable=False)
- hashed_password = Column(String(255), nullable=False)
- created_at = Column(DateTime, default=datetime.utcnow)
复制代码
三、后端核心代码实现
1. 数据库连接配置
backend/app/database.py中使用SQLAlchemy创建引擎,并为SQLite特别设置check_same_thread=False以支持多线程:- SQLALCHEMY_DATABASE_URL = "sqlite:///./db_manager.db"
- engine = create_engine(
- SQLALCHEMY_DATABASE_URL,
- connect_args={"check_same_thread": False},
- )
- SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
- Base = declarative_base()
复制代码 同时定义get_db()作为FastAPI依赖注入,负责每次请求后关闭会话。
2. 密码哈希与JWT签发
在backend/app/crud.py中,使用Passlib的bcrypt方案进行密码哈希,安全性高且与标准JWT结合:- pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
- def get_password_hash(password: str) -> str:
- return pwd_context.hash(password)
- def verify_password(plain_password: str, hashed_password: str) -> bool:
- return pwd_context.verify(plain_password, hashed_password)
复制代码 登录验证通过后,调用create_access_token生成JWT令牌,设置过期时间(通常30分钟,可通过ACCESS_TOKEN_EXPIRE_MINUTES配置):- def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
- to_encode = data.copy()
- expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
- to_encode.update({"exp": expire})
- return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
复制代码
3. 接口鉴权实现
后端通过OAuth2PasswordBearer从请求中提取Bearer Token,解析后获取当前用户。main.py中定义了get_current_user依赖:- def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
- username = crud.decode_token(token)
- if not username:
- raise HTTPException(status_code=401, detail="无效或过期的登录凭证")
- user = crud.get_user_by_username(db, username)
- if not user:
- raise HTTPException(status_code=401, detail="用户不存在")
- return user
复制代码 只要在接口参数中加入current_user: models.User = Depends(get_current_user),该接口即受JWT保护。
4. 只读SQL执行安全控制
为了演示系统的安全性,后端对执行的SQL进行严格校验:仅允许SELECT、PRAGMA、EXPLAIN开头,否则抛出异常。代码位于查询执行模块:- sql = request.sql_text.strip()
- first_word = sql.split(None, 1)[0].lower() if sql else ""
- if first_word not in {"select", "pragma", "explain"}:
- raise ValueError("演示系统仅允许 SELECT/PRAGMA/EXPLAIN 只读语句")
复制代码 执行后通过sqlite3.Row转换为字典列表,便于前端动态渲染表格。
四、前端登录状态处理
前端采用Vue 3 + Vite,令牌统一保存在localStorage中,每次请求通过Fetch API自动添加Authorization头。核心封装在frontend/src/api.js:- export function getToken() {
- return localStorage.getItem('db_manager_token')
- }
- async function request(path, options = {}) {
- const headers = options.headers || {}
- const token = getToken()
- if (token) headers.Authorization = `Bearer ${token}`
- const response = await fetch(`${API_BASE}${path}`, { ...options, headers })
- const data = await response.json().catch(() => ({}))
- if (!response.ok) throw new Error(data.detail || '请求失败')
- return data
- }
复制代码 App.vue在页面加载时检查localStorage中是否存在token,若存在则自动进入系统;退出登录时清除token并跳转到登录页。
五、部署与运行
1. 启动后端(Python 3.8+,建议使用虚拟环境):- cd project/backend
- python3 -m venv .venv
- source .venv/bin/activate
- pip install -r requirements.txt
- uvicorn app.main:app --reload --host 127.0.0.1 --port 8000
复制代码 后端自动创建db_manager.db和demo_data.db,接口文档地址:http://127.0.0.1:8000/docs
2. 启动前端(需要Node.js):- cd project/frontend
- npm install
- npm run dev
复制代码 前端开发服务器默认运行在http://127.0.0.1:5173
3. 使用示例
打开前端后注册账号,登录后在“数据库连接”表单中创建一个指向./demo_data.db的连接。然后在SQL查询台输入:SELECT * FROM employees;,点击“执行只读查询”即可看到示例员工数据。若需复用,可点击“保存为模板”,将SQL存入个人模板列表。
六、总结与扩展思路
本文基于FastAPI和Vue 3实现了一个功能完整的SQLite管理工具,覆盖了用户注册登录、JWT鉴权、只读查询执行、模板管理等核心需求。对于学习Python全栈开发的同学,项目中涉及的密码哈希、JWT、SQLAlchemy模型、FastAPI依赖注入、前端状态管理等都是关键知识点。后续可扩展支持多数据库类型、表结构浏览器、分页查询、角色权限控制、审计日志检索等功能,进一步增强实用性。 |