【Flask】Flask+VUE3.0前后端分离项目
【Flask】Flask+VUE3.0前后端分离项目
- Flask+VUE3.0前后端分离项目
- 一、PostgreSQL数据库存储的表结构设计
- 数据库表结构设计
- 1. 用户表 (`users`)
- 2. 登录记录表 (`login_records`)
- SQL 创建表
- 表关系
- 示例数据插入
- 注意事项
- 二、Flask实现用户登录功能的后端代码,包括与PostgreSQL数据库的交互,使用JWT生成token,并存储登录记录
- 环境准备
- 项目结构
- 代码实现
- 1. `app/__init__.py`
- 2. `app/config.py`
- 3. `app/models.py`
- 4. `app/utils.py`
- 5. `app/routes.py`
- 6. `run.py`
- 7. `.env`
- 8. 数据库迁移
- 数据库表结构
- 总结
- 三、Vue 3.0实现前端部分的代码,包括用户登录功能,并与Flask后端进行交互。
- 1. 创建Vue 3.0项目
- 2. 安装Axios
- 3. 创建登录页面组件
- 4. 配置路由
- 5. 创建受保护页面组件
- 6. 添加主应用文件
- 7. 配置Axios基础URL
- 8. 运行项目
Flask+VUE3.0前后端分离项目
flask+vue3.0搭建前后端分离的web系统,实现用户登录功能,使用PostgreSQL数据库存储用户登录的数据,包括token、登录时间等。
一、PostgreSQL数据库存储的表结构设计
好的,以下是用于存储用户登录数据的PostgreSQL数据库表结构设计:
数据库表结构设计
1. 用户表 (users)
用于存储用户的基本信息。
字段名 数据类型 约束条件 描述 id SERIAL PRIMARY KEY 用户ID username VARCHAR(50) UNIQUE, NOT NULL 用户名 password VARCHAR(255) NOT NULL 密码(加密存储) created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 创建时间 2. 登录记录表 (login_records)
用于存储用户的登录记录,包括token和登录时间。
字段名 数据类型 约束条件 描述 id SERIAL PRIMARY KEY 记录ID user_id INTEGER FOREIGN KEY REFERENCES users(id) 用户ID token VARCHAR(255) NOT NULL JWT Token login_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP 登录时间 expires_at TIMESTAMP NOT NULL Token过期时间 SQL 创建表
以下是创建上述表的SQL语句:
-- 创建用户表 CREATE TABLE users ( id SERIAL PRIMARY KEY, username VARCHAR(50) UNIQUE NOT NULL, password VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 创建登录记录表 CREATE TABLE login_records ( id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL, token VARCHAR(255) NOT NULL, login_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, expires_at TIMESTAMP NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id) );
表关系
- users 表和 login_records 表通过 user_id 字段建立外键关系,login_records 表中的 user_id 字段引用 users 表中的 id 字段。
示例数据插入
以下是一些示例数据插入语句:
-- 插入用户数据 INSERT INTO users (username, password) VALUES ('user1', 'hashed_password1'), ('user2', 'hashed_password2'); -- 插入登录记录数据 INSERT INTO login_records (user_id, token, expires_at) VALUES (1, 'sample_token_1', NOW() + INTERVAL '1 hour'), (2, 'sample_token_2', NOW() + INTERVAL '1 hour');
注意事项
- 密码应使用安全的哈希算法(如bcrypt)进行加密存储,而不是明文存储。
- Token的生成和过期时间应根据实际需求进行管理,例如使用JWT生成token并设置合理的过期时间。
通过上述设计,可以有效地存储用户信息和登录记录,确保系统的安全性和可维护性。
二、Flask实现用户登录功能的后端代码,包括与PostgreSQL数据库的交互,使用JWT生成token,并存储登录记录
环境准备
首先,确保你已经安装了以下Python包:
pip install Flask Flask-SQLAlchemy Flask-Migrate psycopg2-binary PyJWT
项目结构
project/ │ ├── app/ │ ├── __init__.py │ ├── models.py │ ├── routes.py │ ├── config.py │ └── utils.py │ ├── migrations/ │ ├── venv/ │ ├── .env └── run.py
代码实现
1. app/__init__.py
初始化Flask应用和数据库:
from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate import os db = SQLAlchemy() migrate = Migrate() def create_app(): app = Flask(__name__) app.config.from_object('app.config.Config') db.init_app(app) migrate.init_app(app, db) from app.routes import main as main_blueprint app.register_blueprint(main_blueprint) return app
2. app/config.py
配置文件,包含数据库连接和JWT密钥:
import os class Config: SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL', 'postgresql://username:password@localhost/dbname') SQLALCHEMY_TRACK_MODIFICATIONS = False SECRET_KEY = os.getenv('SECRET_KEY', 'your_secret_key') JWT_SECRET_KEY = os.getenv('JWT_SECRET_KEY', 'your_jwt_secret_key')
3. app/models.py
定义数据库模型:
from app import db from datetime import datetime 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(255), nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) class LoginRecord(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) token = db.Column(db.String(255), nullable=False) login_time = db.Column(db.DateTime, default=datetime.utcnow) expires_at = db.Column(db.DateTime, nullable=False) user = db.relationship('User', backref=db.backref('login_records', lazy=True))
4. app/utils.py
辅助函数,用于生成和验证JWT token:
import jwt from datetime import datetime, timedelta from app import app from app.models import User def generate_token(user_id): payload = { 'exp': datetime.utcnow() + timedelta(hours=1), 'iat': datetime.utcnow(), 'sub': user_id } return jwt.encode(payload, app.config['JWT_SECRET_KEY'], algorithm='HS256') def decode_token(token): try: payload = jwt.decode(token, app.config['JWT_SECRET_KEY'], algorithms=['HS256']) return payload['sub'] except jwt.ExpiredSignatureError: return None except jwt.InvalidTokenError: return None
5. app/routes.py
定义路由和视图函数:
from flask import Blueprint, request, jsonify from app import db from app.models import User, LoginRecord from app.utils import generate_token, decode_token main = Blueprint('main', __name__) @main.route('/register', methods=['POST']) def register(): data = request.get_json() if User.query.filter_by(username=data['username']).first(): return jsonify({'message': 'Username already exists'}), 400 new_user = User(username=data['username'], password=data['password']) db.session.add(new_user) db.session.commit() return jsonify({'message': 'User registered successfully'}), 201 @main.route('/login', methods=['POST']) def login(): data = request.get_json() user = User.query.filter_by(username=data['username']).first() if user and user.password == data['password']: token = generate_token(user.id) login_record = LoginRecord(user_id=user.id, token=token, expires_at=datetime.utcnow() + timedelta(hours=1)) db.session.add(login_record) db.session.commit() return jsonify({'token': token, 'expires_at': login_record.expires_at}), 200 return jsonify({'message': 'Invalid username or password'}), 401 @main.route('/protected', methods=['GET']) def protected(): token = request.headers.get('Authorization').split(" ")[1] user_id = decode_token(token) if user_id: return jsonify({'message': 'This is a protected route', 'user_id': user_id}), 200 return jsonify({'message': 'Token is invalid or has expired'}), 401
6. run.py
运行Flask应用:
from app import create_app app = create_app() if __name__ == '__main__': app.run(debug=True)
7. .env
环境变量文件,用于存储敏感信息:
(图片来源网络,侵删)DATABASE_URL=postgresql://username:password@localhost/dbname SECRET_KEY=your_secret_key JWT_SECRET_KEY=your_jwt_secret_key
8. 数据库迁移
初始化数据库迁移:
flask db init flask db migrate -m "Initial migration." flask db upgrade
数据库表结构
确保你的PostgreSQL数据库中已经创建了以下表:
(图片来源网络,侵删)- users 表,包含 id, username, password, created_at 字段。
- login_records 表,包含 id, user_id, token, login_time, expires_at 字段。
总结
以上代码展示了如何使用Flask和PostgreSQL实现一个简单的用户登录功能,包括用户注册、登录、生成JWT token以及记录登录信息。你可以根据需要进一步扩展和优化代码,例如添加密码哈希、错误处理、日志记录等功能。
三、Vue 3.0实现前端部分的代码,包括用户登录功能,并与Flask后端进行交互。
1. 创建Vue 3.0项目
首先,确保你已经安装了Vue CLI。如果没有安装,可以使用以下命令进行安装:
(图片来源网络,侵删)npm install -g @vue/cli
然后,创建一个新的Vue 3.0项目:
vue create vue3-login
选择默认配置或自定义配置,根据需要选择Vue 3.0。
2. 安装Axios
Axios是一个用于发送HTTP请求的库。在项目目录中安装Axios:
cd vue3-login npm install axios
3. 创建登录页面组件
在 src/components 目录下创建一个 Login.vue 文件:
Login
Username: Password: Login{{ errorMessage }}
import axios from 'axios'; export default { data() { return { username: '', password: '', errorMessage: '' }; }, methods: { async login() { try { const response = await axios.post('http://localhost:5000/login', { username: this.username, password: this.password }); if (response.data.token) { localStorage.setItem('token', response.data.token); localStorage.setItem('expires_at', response.data.expires_at); this.$router.push('/protected'); } } catch (error) { this.errorMessage = 'Invalid username or password'; } } } }; .login-container { max-width: 400px; margin: 0 auto; padding: 20px; border: 1px solid #ccc; border-radius: 5px; } form div { margin-bottom: 15px; } button { width: 100%; padding: 10px; background-color: #42b983; color: white; border: none; border-radius: 5px; cursor: pointer; } button:hover { background-color: #369d72; }4. 配置路由
在 src/router/index.js 中配置路由:
import { createRouter, createWebHistory } from 'vue-router'; import Login from '../components/Login.vue'; const routes = [ { path: '/', name: 'Login', component: Login }, { path: '/protected', name: 'Protected', component: () => import('../components/Protected.vue'), meta: { requiresAuth: true } } ]; const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes }); router.beforeEach((to, from, next) => { const token = localStorage.getItem('token'); if (to.matched.some(record => record.meta.requiresAuth) && !token) { next('/'); } else { next(); } }); export default router;
5. 创建受保护页面组件
显示登录时间和处理登出功能。
在 src/components 目录下创建 Protected.vue 文件:
Protected Page
Welcome! You are logged in.
Last login: {{ loginTime }}
Logout export default { data() { return { loginTime: '' }; }, created() { this.checkLoginTime(); }, methods: { checkLoginTime() { const expiresAt = localStorage.getItem('expires_at'); if (expiresAt) { this.loginTime = new Date(expiresAt).toLocaleString(); } }, logout() { localStorage.removeItem('token'); localStorage.removeItem('expires_at'); this.$router.push('/'); } } }; .protected-container { max-width: 400px; margin: 0 auto; padding: 20px; border: 1px solid #ccc; border-radius: 5px; } button { width: 100%; padding: 10px; background-color: #e74c3c; color: white; border: none; border-radius: 5px; cursor: pointer; } button:hover { background-color: #c0392b; }6. 添加主应用文件
在 src/App.vue 中,确保你的应用有一个基本的布局和导航:
export default { name: 'App' }; #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; }
7. 配置Axios基础URL
在 src 目录下创建一个 axios.js 文件,用于配置Axios的基础URL:
import axios from 'axios'; axios.defaults.baseURL = 'http://localhost:5000'; export default axios;
8. 运行项目
确保你的Flask后端服务已经启动,并且能够处理登录请求。然后,运行Vue项目:
npm run serve
现在,你应该能够访问前端应用,并在 / 路径上看到登录页面。成功登录后,用户将被重定向到受保护的 /protected 页面。
虽然本次会话只涉及前端代码,但为了完整性,这里提供一个简单的Flask后端代码示例,用于处理用户登录和生成Token:这个Flask后端示例处理用户登录请求,并生成一个JWT Token,前端可以使用这个Token进行身份验证。注意,这只是一个简单的示例,实际应用中应包含更多的安全措施和功能。
- users 表和 login_records 表通过 user_id 字段建立外键关系,login_records 表中的 user_id 字段引用 users 表中的 id 字段。