我的项目 2:Flask 身份验证系统(Python + Flask)
发布: (2025年12月14日 GMT+8 01:30)
5 min read
原文: Dev.to
Source: Dev.to

🔐 Flask 认证系统
我一直对我们每天使用的网站是如何构建的感到好奇。
我们不断地使用注册、登录和退出等功能,但大多数人从未真正了解背后发生了什么。
我也不例外——这种好奇心与日俱增,我想亲自体验其结构。
于是我决定从零开始构建它,希望通过动手实践,最终弄清这些系统到底是如何运作的。
📂 1. 项目结构
auth_blog/
│── main.py
│── users.db (auto-created)
└── templates/
├── home.html
├── signup.html
└── login.html
🧠 2. 项目功能
- 用户注册(存储哈希密码)
- 带会话管理的用户登录
- 使用自定义
login_required装饰器的受保护仪表盘页面 - 退出登录功能
- 基础的迷你博客 UI 布局
这个结构几乎是所有现代 Web 应用的基础。
🖥️ 3. 后端代码 (main.py)
from flask import Flask, render_template, request, redirect, session
import sqlite3
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
app.secret_key = "super_secret_key"
# Login‑required decorator
def login_required(func):
def wrapper(*args, **kwargs):
if "user_id" not in session:
return redirect("/login")
return func(*args, **kwargs)
wrapper.__name__ = func.__name__
return wrapper
# Initialize database
def init_db():
conn = sqlite3.connect("users.db")
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL
)
""")
conn.commit()
conn.close()
init_db()
# Signup
@app.route("/signup", methods=["GET", "POST"])
def signup():
if request.method == "POST":
username = request.form["username"]
password = request.form["password"]
hashed_pw = generate_password_hash(password)
conn = sqlite3.connect("users.db")
cur = conn.cursor()
try:
cur.execute(
"INSERT INTO users (username, password) VALUES (?, ?)",
(username, hashed_pw)
)
conn.commit()
except sqlite3.IntegrityError:
return "Signup failed: Username already exists."
finally:
conn.close()
return redirect("/login")
return render_template("signup.html")
# Login
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form["username"]
password = request.form["password"]
conn = sqlite3.connect("users.db")
cur = conn.cursor()
cur.execute(
"SELECT id, username, password FROM users WHERE username = ?",
(username,)
)
user = cur.fetchone()
conn.close()
if user and check_password_hash(user[2], password):
session["user_id"] = user[0]
session["username"] = user[1]
return redirect("/dashboard")
else:
return "Login failed: Invalid username or password."
return render_template("login.html")
# Dashboard (protected)
@app.route("/dashboard")
@login_required
def dashboard():
return f"Welcome, {session['username']}! (Dashboard Page)"
# Logout
@app.route("/logout")
def logout():
session.clear()
return redirect("/login")
# Home
@app.route("/")
def home():
return render_template("home.html")
if __name__ == "__main__":
app.run(debug=True)
🖼️ 4. 模板
🏠 home.html
<!DOCTYPE html>
<html>
<head>
<title>Mini Blog</title>
<style>
body { font-family: sans-serif; padding: 20px; background-color: #f4f7f9; }
.post {
border: 1px solid #ddd;
padding: 15px;
margin-bottom: 15px;
border-radius: 8px;
background-color: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.top {
display: flex; justify-content: space-between;
align-items: center; border-bottom: 2px solid #007bff;
margin-bottom: 20px; padding-bottom: 10px;
}
a { text-decoration: none; color: #007bff; font-weight: bold; }
</style>
</head>
<body>
<div class="top">
<h1>Mini Blog Posts</h1>
<a href="/new">Write New Post →</a>
</div>
{% for post in posts %}
<div class="post">
<h3>{{ post[1] }}</h3>
<p>{{ post[2] }}</p>
</div>
{% endfor %}
{% if not posts %}
<p>No posts yet. Start writing your first entry!</p>
{% endif %}
</body>
</html>
🔑 login.html
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
<style>
body { font-family: sans-serif; padding: 20px; }
form { display: flex; flex-direction: column; width: 300px; gap: 10px; }
input { padding: 10px; border: 1px solid #ccc; border-radius: 4px; }
button { padding: 10px; background: #28a745; color: white;
border: none; border-radius: 4px; cursor: pointer; }
button:hover { background: #1e7e34; }
</style>
</head>
<body>
<h2>Log In</h2>
<form method="POST" action="/login">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Log In</button>
</form>
</body>
</html>
📝 signup.html
<!DOCTYPE html>
<html>
<head>
<title>Sign Up</title>
<style>
body { font-family: sans-serif; padding: 20px; }
form { display: flex; flex-direction: column; width: 300px; gap: 10px; }
input { padding: 10px; border: 1px solid #ccc; border-radius: 4px; }
button { padding: 10px; background: #007bff; color: white;
border: none; border-radius: 4px; cursor: pointer; }
button:hover { background: #0056b3; }
</style>
</head>
<body>
<h2>Sign Up</h2>
<form method="POST" action="/signup">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Register</button>
</form>
</body>
</html>
🔧 5. 亲自尝试 — 简单改进
- 在已认证的仪表盘中添加帖子创建功能
- 允许用户编辑/删除自己的帖子
- 为帖子添加时间戳
- 添加密码重置功能
- 使用 CSS 样式表改进 UI
这些小改进将帮助你更深入地理解 Web 认证和后端结构。尝试做一两项修改,看看这个项目如何快速演变成真正的应用!