基于Python&MySQL的用户数据库:密码加盐哈希存储及Flask适配问题
Flask + MySQL 安全密码存储与验证方案
一、数据库表设计优化
先明确两个核心方案的表结构:
方案1:用Bcrypt(推荐,自动管理盐值)
Bcrypt会自动把盐值嵌入哈希结果,无需单独存储盐字段,表结构更简洁:
CREATE TABLE user_passwords ( user_id INT PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, FOREIGN KEY (user_id) REFERENCES users(user_id) );
方案2:自定义盐+SHA256(手动存储盐值)
如果坚持单独存盐,表结构如下:
CREATE TABLE user_passwords ( user_id INT PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, salt VARCHAR(255) NOT NULL, password_hash VARCHAR(64) NOT NULL, -- SHA256哈希固定64位十六进制 FOREIGN KEY (user_id) REFERENCES users(user_id) );
二、Flask代码实现(适配request.form)
1. Bcrypt方案(最安全且易维护)
先安装依赖:
pip install flask-bcrypt
Flask应用核心代码:
from flask import Flask, request from flask_bcrypt import Bcrypt import mysql.connector app = Flask(__name__) bcrypt = Bcrypt(app) # 配置MySQL连接(替换为你的实际参数) db = mysql.connector.connect( host="localhost", user="your_db_user", password="your_db_pwd", database="your_db_name" ) cursor = db.cursor() # 注册接口:处理表单数据并存储 @app.route('/register', methods=['POST']) def register(): # 从request.form获取所有字段 user_id = request.form.get('user_id') first_name = request.form.get('first_name') last_name = request.form.get('last_name') email = request.form.get('email') dob = request.form.get('dob') password = request.form.get('password') # 1. 插入基础用户信息到users表 insert_user_sql = """ INSERT INTO users (user_id, first_name, last_name, email, dob) VALUES (%s, %s, %s, %s, %s) """ cursor.execute(insert_user_sql, (user_id, first_name, last_name, email, dob)) # 2. 生成Bcrypt哈希(自动包含盐值,转字符串存库) pw_hash = bcrypt.generate_password_hash(password).decode('utf-8') # 3. 插入哈希到密码表 insert_pw_sql = """ INSERT INTO user_passwords (user_id, email, password_hash) VALUES (%s, %s, %s) """ cursor.execute(insert_pw_sql, (user_id, email, pw_hash)) db.commit() return "注册成功" # 登录接口:验证密码 @app.route('/login', methods=['POST']) def login(): email = request.form.get('email') password = request.form.get('password') # 从库中取出存储的哈希 cursor.execute("SELECT password_hash FROM user_passwords WHERE email = %s", (email,)) result = cursor.fetchone() if result: stored_hash = result[0] # 验证密码匹配 if bcrypt.check_password_hash(stored_hash, password): return "登录成功" return "密码错误" return "用户不存在"
2. 自定义盐+SHA256方案
如果必须手动管理盐值,用secrets生成安全随机盐:
import secrets import hashlib # 注册接口 @app.route('/register', methods=['POST']) def register(): # 其他字段获取同上 password = request.form.get('password') # 生成16字节随机盐(转32位十六进制字符串) salt = secrets.token_hex(16) # 加盐后哈希 salted_pw = password + salt pw_hash = hashlib.sha256(salted_pw.encode('utf-8')).hexdigest() # 插入盐和哈希到库 insert_pw_sql = """ INSERT INTO user_passwords (user_id, email, salt, password_hash) VALUES (%s, %s, %s, %s) """ cursor.execute(insert_pw_sql, (user_id, email, salt, pw_hash)) db.commit() return "注册成功" # 登录验证 @app.route('/login', methods=['POST']) def login(): email = request.form.get('email') password = request.form.get('password') cursor.execute("SELECT salt, password_hash FROM user_passwords WHERE email = %s", (email,)) result = cursor.fetchone() if result: salt, stored_hash = result # 用相同盐生成哈希对比 computed_hash = hashlib.sha256((password + salt).encode('utf-8')).hexdigest() if computed_hash == stored_hash: return "登录成功" return "密码错误" return "用户不存在"
三、你之前适配失败的常见原因
- 前端表单密码输入框的
name属性不是password:确保是<input type="password" name="password">,否则request.form.get('password')会返回None - 哈希结果未转字符串:Bcrypt生成的是字节串,必须用
decode('utf-8')转成字符串才能存入MySQL - 数据库字段长度不足:Bcrypt哈希约60位,需设
VARCHAR(255);SHA256哈希是64位,设VARCHAR(64)即可
内容的提问来源于stack exchange,提问作者excalibur47
相关产品推荐
相关产品推荐

