使用 werkzeug 安全地处理密码
假设我们要实现一个登录注册的功能,最简单的方式是先创建一个表,有 username 和 password 字段,然后再编写相应的登录和注册接口。
创建表
以下是一个简单的例子,展示了如何创建一个用户表并定义一些基本的操作:
import sqlite3def create_connection(db_file):""" 创建数据库连接 """conn = Nonetry:conn = sqlite3.connect(db_file)return connexcept Exception as e:print(e)return conndef create_table(conn):""" 创建一个表 """try:cursor = conn.cursor()cursor.execute("""CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY,username TEXT NOT NULL,password TEXT NOT NULL);""")conn.commit()except Exception as e:print(e)def add_user(conn, username, password):""" 向用户表中添加一个新用户 """try:cursor = conn.cursor()cursor.execute("INSERT INTO users (username, password) VALUES (?, ?)", (username, password))conn.commit()except Exception as e:print(e)def main():database = "users.db"# 创建数据库连接conn = create_connection(database)# 创建表if conn is not None:create_table(conn)# 添加用户示例add_user(conn, 'username1', 'password1')else:print("无法创建数据库连接。")if __name__ == '__main__':main()
注意,这个示例中使用明文存储密码,这在实际应用中是不安全的。因此,应该使用像 werkzeug.security
中的 generate_password_hash
和 check_password_hash
这样的方法来安全地处理密码。
- 安装 Werkzeug:
pip install Werkzeug
- 修改添加用户函数:使用
generate_password_hash
来存储密码的哈希值,而不是明文密码。 - 创建一个验证用户的函数:使用
check_password_hash
来验证提交的密码是否与存储的哈希匹配。
import sqlite3
from werkzeug.security import generate_password_hash, check_password_hashdef create_connection(db_file):""" 创建数据库连接 """# ... 代码不变 ...def create_table(conn):""" 创建一个表 """# ... 代码不变 ...def add_user(conn, username, password):""" 向用户表中添加一个新用户 """hashed_password = generate_password_hash(password)try:cursor = conn.cursor()cursor.execute("INSERT INTO users (username, password) VALUES (?, ?)", (username, hashed_password))conn.commit()except Exception as e:print(e)def verify_user(conn, username, password):""" 验证用户凭据 """try:cursor = conn.cursor()cursor.execute("SELECT password FROM users WHERE username = ?", (username,))stored_password = cursor.fetchone()if stored_password and check_password_hash(stored_password[0], password):return Trueelse:return Falseexcept Exception as e:print(e)return False# main 函数和其他部分的代码不变
接口编写
首先,定义 User 模型
from database import dbclass User(db.Model):id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(80), unique=True, nullable=False)password = db.Column(db.String(120), nullable=False)def to_dict(self):return {'id': self.id,'username': self.username# 注意:不要返回密码}
然后,在 Flask 应用中添加注册和登录路由处理函数:
from flask import Flask, request, jsonify
from werkzeug.security import generate_password_hash, check_password_hash
# ... 其他导入 ...# ... Flask 应用的其他部分 ...@app.route('/api/register', methods=['POST'])
def register():data = request.get_json()# 确认数据有效性username = data.get('username')password = data.get('password')if not username or not password:return jsonify({'message': 'Missing username or password'}), 400# 检查用户名是否已存在if User.query.filter_by(username=username).first():return jsonify({'message': 'Username already exists'}), 400# 创建新用户hashed_password = generate_password_hash(password)new_user = User(username=username, password=hashed_password)db.session.add(new_user)db.session.commit()return jsonify({'message': 'User created successfully', 'user': new_user.to_dict()}), 201@app.route('/api/login', methods=['POST'])
def login():data = request.get_json()username = data.get('username')password = data.get('password')if not username or not password:return jsonify({'message': 'Missing username or password'}), 400# 检查用户是否存在user = User.query.filter_by(username=username).first()if user and check_password_hash(user.password, password):# 在这里,你应该生成并返回一个认证令牌return jsonify({'message': 'Login successful', 'user': user.to_dict()}), 200else:return jsonify({'message': 'Invalid credentials'}), 401# ... Flask 应用的其他部分 ...if __name__ == '__main__':app.run(debug=True)
注意
使用 Werkzeug 的 generate_password_hash
函数对密码进行哈希处理后,原始密码将不再可见,因此不再存储明文密码。这是哈希算法的一种基本原则,密码不应该以明文形式存储,以提高安全性。
因此,一旦密码被哈希处理,就不再能够直接查看密码的明文值。验证密码时,您将使用 check_password_hash
函数来比较哈希值,而不是查看明文密码。
当然,我们可以使用 Werkzeug 验证密码:、
from werkzeug.security import generate_password_hash, check_password_hash# 生成哈希密码
password = "userpassword123"
hashed_password = generate_password_hash(password)# 检查密码
user_input_password = "userpassword123" # 用户输入的密码
if check_password_hash(hashed_password, user_input_password):print("密码正确")
else:print("密码错误")
在上述示例中,generate_password_hash 用于创建哈希密码,而 check_password_hash 用于验证用户提供的密码是否与哈希密码匹配。由于哈希是单向的,所以无法从哈希密码还原出明文密码。