flask vue3 admin 怎么搭建前后端分离的后台管理项目?
为啥选 Flask + Vue3 组合做后台管理系统?
做后台管理系统时,技术选型得兼顾开发效率和可维护性,选 Flask 做后端,是因为它轻量灵活,没太多冗余配置,想加功能就装扩展(比如用 Flask-RESTful 快速写接口、Flask-SQLAlchemy 连数据库),适合快速迭代。
前端选 Vue3 呢,Composition API 让逻辑复用更方便,写复杂页面时代码结构更清晰;而且生态里像 Element Plus 这种 UI 库组件丰富,表格、表单、弹窗这些后台常用组件直接拿过来改,省不少时间。
前后端分离还有个隐形优势:团队能分工,前端专注交互和页面逻辑,后端专心搞数据和业务规则,开发时还能并行推进——前端用 mock 数据先做页面,后端单独测接口,联调时换真实地址就行,效率拉满。
搭建前得准备哪些环境和工具?
环境和工具准备到位,后面少踩坑。
后端环境:得装 Python(建议 3.8+,稳定还兼容新库),然后搞个虚拟环境(用 venv 或者 conda,隔离项目依赖),再装核心库:Flask(框架本身)、Flask-SQLAlchemy(操作数据库)、PyJWT(做 token 鉴权)、flask-cors(处理跨域)这些。
前端环境:Node.js 得 16+ 版本,用 Vite 或者 Vue CLI 初始化项目(推荐 Vite,打包和热更新更快),然后装 Element Plus(UI 库)、Pinia(状态管理,替代 Vuex 更轻量)、axios(发请求)这些依赖。
工具辅助:VSCode 装 Python Vue Language Features 插件,写代码时自动补全、查错;Postman 用来测后端接口,确保返回符合预期;数据库工具选 Navicat 或者 DBeaver,方便可视化操作表结构。
Flask 后端怎么快速写出接口和鉴权?
后端核心是提供接口和控制权限,按步骤来:
项目结构分层
建个 app 文件夹,里面分模块:
routes:放路由和视图函数,比如用户登录、增删改查的接口;models:定义数据库模型(用户、角色、权限这些表结构);utils:工具函数,比如生成 JWT、密码加密;config.py:存配置(数据库地址、JWT 密钥)。
数据库模型示例
用 Flask-SQLAlchemy 定义用户表:
from app import db, bcrypt # bcrypt 是密码加密工具
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True, nullable=False)
password = db.Column(db.String(100), nullable=False)
role = db.Column(db.String(20), default='user') # 简单角色控制,复杂场景用关联表
def set_password(self, password):
self.password = bcrypt.generate_password_hash(password).decode('utf-8')
def check_password(self, password):
return bcrypt.check_password_hash(self.password, password)
路由与鉴权
写登录接口,验证成功后发 token:
from flask import request, jsonify
from app.routes import bp
from app.models import User
import jwt
from datetime import datetime, timedelta
@bp.route('/login', methods=['POST'])
def login():
data = request.get_json()
user = User.query.filter_by(username=data['username']).first()
if not user or not user.check_password(data['password']):
return jsonify({'msg': '账号或密码错误'}), 401
# 生成 token,过期时间设为2小时
token = jwt.encode(
{'id': user.id, 'exp': datetime.utcnow() + timedelta(hours=2)},
app.config['SECRET_KEY'],
algorithm='HS256'
)
return jsonify({'token': token}), 200
鉴权用装饰器,保护需要登录的接口:
from functools import wraps
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.headers.get('Authorization')
if not token:
return jsonify({'msg': '缺少 token'}), 401
try:
data = jwt.decode(token.split(' ')[1], app.config['SECRET_KEY'], algorithms=['HS256'])
current_user = User.query.get(data['id'])
except:
return jsonify({'msg': 'token 无效'}), 401
return f(current_user, *args, **kwargs)
return decorated
# 用装饰器保护接口
@bp.route('/user', methods=['GET'])
@token_required
def get_user(current_user):
return jsonify({'username': current_user.username}), 200
处理跨域
装 flask-cors 后,在 app.py 里配置:
from flask_cors import CORS
app = Flask(__name__)
CORS(app, resources={r"/api/*": {"origins": "http://localhost:5173"}}) # 前端开发地址
Vue3 前端怎么构建页面和处理请求?
前端核心是页面交互和请求管理,步骤如下:
初始化项目与 UI 库
用 Vite 建项目:npm create vite@latest my-admin --template vue,然后装 Element Plus:
npm install element-plus @element-plus/icons-vue
在 main.js 全局注册:
import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as Icons from '@element-plus/icons-vue'
const app = createApp(App)
app.use(ElementPlus)
// 全局注册图标
for (const [key, component] of Object.entries(Icons)) {
app.component(key, component)
}
app.mount('#app')
路由与状态管理
用 vue-router 配页面路由(登录、仪表盘、用户管理):
import { createRouter, createWebHistory } from 'vue-router'
import Login from './views/Login.vue'
import Dashboard from './views/Dashboard.vue'
import UserManage from './views/UserManage.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/login', name: 'Login', component: Login },
{ path: '/', name: 'Dashboard', component: Dashboard, meta: { requiresAuth: true } },
{ path: '/user', name: 'UserManage', component: UserManage, meta: { requiresAuth: true } }
]
})
用 Pinia 存用户信息和 token:
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
token: localStorage.getItem('token') || '',
username: '',
role: ''
}),
actions: {
setUserInfo(info) {
this.token = info.token
this.username = info.username
this.role = info.role
localStorage.setItem('token', info.token)
},
logout() {
this.$reset()
localStorage.removeItem('token')
}
}
})
请求封装(axios)
封装 axios 统一加 token、处理错误:
import axios from 'axios'
import { useUserStore } from '@/stores/user'
import { ElMessage } from 'element-plus'
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL, // 从环境变量拿后端地址
timeout: 5000
})
// 请求拦截器:加 token 到请求头
request.interceptors.request.use(config => {
const userStore = useUserStore()
if (userStore.token) {
config.headers.Authorization = `Bearer ${userStore.token}`
}
return config
}, error => {
return Promise.reject(error)
})
// 响应拦截器:处理错误
request.interceptors.response.use(response => {
return response.data
}, error => {
if (error.response.status === 401) {
// token 过期,跳登录页
const userStore = useUserStore()
userStore.logout()
window.location.href = '/login'
ElMessage.error('登录状态失效,请重新登录')
} else {
ElMessage.error(error.response.data.msg || '请求失败')
}
return Promise.reject(error)
})
export default request
前后端联调时容易踩哪些坑?
联调是“发现问题 - 改问题”的过程,这些坑要注意:
跨域配置不对
后端 flask-cors 配置的 origins 要和前端实际地址一致,开发时前端是 http://localhost:5173,生产是线上域名,别偷懒用 (生产环境有安全风险)。
接口地址不统一
前端用 .env.development 和 .env.production 区分开发/生产环境的后端地址:
# 开发环境 VITE_API_BASE_URL = 'http://localhost:5000' # 生产环境 VITE_API_BASE_URL = 'https://your-domain.com/api'
token 传递丢了
前端要确保所有请求的请求头都带 Authorization,axios 拦截器里加了逻辑,但如果手动发请求(比如用 fetch),得自己加头,不然后端鉴权失败。
响应格式不统一
后端接口返回要固定格式,
{
"code": 200,
"data": {},
"msg": "操作成功"
}
前端拦截器统一处理 code,code !== 200 就弹错误提示,别让不同接口返回格式五花八门,前端处理逻辑乱套。
后台管理系统的权限该怎么设计?
权限要从后端控制接口和前端控制页面/按钮两方面做:
后端:RBAC 模型
简单场景用“用户 - 角色 - 权限”关联,比如给角色分配权限(如 user:add user:edit),用户关联角色,后端接口加权限装饰器:
def require_permission(perm):
def decorator(f):
@wraps(f)
def wrapped(current_user, *args, **kwargs):
if perm not in current_user.role.permissions: # 假设角色表存了权限字符串
return jsonify({'msg': '没有权限'}), 403
return f(current_user, *args, **kwargs)
return wrapped
return decorator
# 保护需要权限的接口
@bp.route('/user/add', methods=['POST'])
@token_required
@require_permission('user:add')
def add_user(current_user):
# ... 逻辑
前端:动态控制页面和按钮
-
页面权限:路由守卫判断,比如某个页面需要
user:edit权限,在路由meta里加requiresPermission: 'user:edit',然后在beforeEach里检查:router.beforeEach((to, from, next) => { const userStore = useUserStore() if (to.meta.requiresPermission) { if (userStore.permissions.includes(to.meta.requiresPermission)) { next() } else { next('/403') // 无权限页面 } } else { next() } }) -
按钮权限:用自定义指令,比如控制“删除”按钮只给有权限的人看:
// 自定义指令 permission.js import { useUserStore } from '@/stores/user' export const permissionDirective = { mounted(el, binding) { const userStore = useUserStore() const perm = binding.value if (!userStore.permissions.includes(perm)) { el.parentNode?.removeChild(el) // 移除按钮 } } } // 全局注册指令 app.directive('permission', permissionDirective) // 页面中使用 <el-button v-permission="'user:delete'">删除</el-button>
项目部署到线上要注意什么?
部署要让前后端稳定跑起来,这些细节别漏:
后端部署:Gunicorn + Nginx
-
用
Gunicorn启动 Flask(性能比内置服务器好):gunicorn -w 4 -b 127.0.0.1:8000 app:app # 4 个 worker,绑定 8000 端口
-
Nginx 反向代理,把
/api开头的请求转发给 Gunicorn,静态资源给前端:server { listen 80; server_name your-domain.com; location /api { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location / { root /var/www/frontend/dist; # 前端打包后的 dist 目录 try_files $uri $uri/ /index.html; # 处理前端 history 模式路由 } }
前端部署:打包与静态资源
执行 npm run build 生成 dist 文件夹,传到服务器的 Nginx 静态目录,注意生产环境要把 .env.production 里的后端地址改成线上域名。
数据库与安全
- 数据库用 MySQL 或 PostgreSQL,部署时配好字符集(如
utf8mb4)和用户权限,避免注入风险。 - 用
Flask-Migrate做数据库迁移,改模型后执行flask db migrate和flask db upgrade,保证表结构同步。 - 开启 HTTPS:用 Let’s Encrypt 申请免费证书,Nginx 配置 443 端口,强制 HTTP 跳 HTTPS。
实际开发中还有哪些细节要注意?
这些“小细节”能避免后期返工:
- 密码安全:后端存密码别明文,用
werkzeug.security里的generate_password_hash和check_password_hash加密。 - JWT 配置:token 过期时间别太长(2 小时),同时搞个 refresh token 续期,避免用户频繁登录。
- 路由守卫兜底:前端路由加
requiresAuth元信息,没登录就跳登录页,防止直接输 URL 绕开权限。 - 错误提示友好:后端返回错误码时,前端用
ElMessage弹提示(用户名已存在”“token 过期”),别让用户看空白页懵圈。 - 代码规范:后端用
flake8检查语法,前端用ESLint格式化代码,团队协作时风格统一,维护成本低。
搭建 flask + vue3 admin 项目,核心是前后端各司其职+细节落地,从环境准备到权限设计,每一步都要结合业务场景调整——比如简单项目用角色判断权限,复杂项目用 RBAC 细粒度控制,多测多调,遇到问题拆分成“前端请求→后端接口→数据库操作”环节排查,慢慢就理顺了~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网

