Python OPT认证系统(结合SQLite数据库)
下面是一个完整的OPT认证系统实现,使用SQLite数据库存储用户密钥,并提供了用户注册、登录和OPT验证功能。
import pyotp
import sqlite3
import hashlib
import time
import os
from getpass import getpass
from datetime import datetime, timedelta
# 初始化数据库
def init_db():
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
# 创建用户表
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
totp_secret TEXT NOT NULL,
failed_attempts INTEGER DEFAULT 0,
locked_until TEXT,
last_login TEXT
)
''')
# 创建登录日志表
cursor.execute('''
CREATE TABLE IF NOT EXISTS login_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER,
timestamp TEXT NOT NULL,
ip_address TEXT,
success INTEGER DEFAULT 0,
FOREIGN KEY (user_id) REFERENCES users (id)
)
''')
conn.commit()
conn.close()
# 注册新用户
def register_user():
username = input("请输入用户名: ").strip()
# 检查用户名是否已存在
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
cursor.execute("SELECT id FROM users WHERE username = ?", (username,))
if cursor.fetchone():
print("用户名已存在!")
conn.close()
return
# 密码处理
password = getpass("请输入密码: ").strip()
if len(password) < 6:
print("密码长度至少为6个字符!")
conn.close()
return
password_hash = hashlib.sha256(password.encode()).hexdigest()
# 生成TOTP密钥
totp_secret = pyotp.random_base32()
print("\n安全提示:请妥善保存您的OPT恢复密钥,以便在无法访问认证器时使用")
print(f"您的OPT恢复密钥: {totp_secret}")
print("\n请使用Google Authenticator或类似应用扫描以下二维码:")
# 生成TOTP URI和二维码
totp_uri = pyotp.totp.TOTP(totp_secret).provisioning_uri(
name=username,
issuer_name="Python OPT系统"
)
# 生成二维码(需要安装qrcode模块)
try:
import qrcode
qr = qrcode.QRCode()
qr.add_data(totp_uri)
qr.print_ascii(invert=True)
except ImportError:
print("未安装qrcode库,无法显示二维码。请手动输入密钥:", totp_secret)
# 插入用户数据
cursor.execute('''
INSERT INTO users (username, password_hash, totp_secret)
VALUES (?, ?, ?)
''', (username, password_hash, totp_secret))
conn.commit()
conn.close()
print("\n用户注册成功!")
# 用户登录
def login_user():
username = input("用户名: ").strip()
password = getpass("密码: ").strip()
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
# 获取用户信息
cursor.execute('''
SELECT id, password_hash, totp_secret, failed_attempts, locked_until
FROM users
WHERE username = ?
''', (username,))
user = cursor.fetchone()
if not user:
print("用户名或密码错误!")
log_login_attempt(None, False)
conn.close()
return None
user_id, stored_hash, totp_secret, failed_attempts, locked_until = user
# 检查账户是否被锁定
if locked_until:
lock_time = datetime.fromisoformat(locked_until)
if datetime.now() < lock_time:
remaining = lock_time - datetime.now()
print(f"账户已被锁定,请在 {int(remaining.total_seconds()//60)} 分 {int(remaining.total_seconds()%60)} 秒后重试!")
log_login_attempt(user_id, False)
conn.close()
return None
# 验证密码
if hashlib.sha256(password.encode()).hexdigest() != stored_hash:
print("用户名或密码错误!")
new_attempts = failed_attempts + 1 if failed_attempts is not None else 1
# 锁定账户逻辑
if new_attempts >= 3:
lock_time = datetime.now() + timedelta(minutes=5)
print("连续登录失败次数过多,账户已被锁定5分钟!")
cursor.execute('''
UPDATE users
SET failed_attempts = ?, locked_until = ?
WHERE id = ?
''', (new_attempts, lock_time.isoformat(), user_id))
else:
print(f"登录失败!剩余尝试次数: {3 - new_attempts}")
cursor.execute('''
UPDATE users
SET failed_attempts = ?
WHERE id = ?
''', (new_attempts, user_id))
conn.commit()
log_login_attempt(user_id, False)
conn.close()
return None
# 验证OPT
totp = pyotp.TOTP(totp_secret)
opt_code = input("请输入OPT验证码: ").strip()
if not totp.verify(opt_code):
print("OPT验证码错误!")
log_login_attempt(user_id, False)
conn.close()
return None
# 登录成功,重置失败计数
cursor.execute('''
UPDATE users
SET failed_attempts = 0, locked_until = NULL, last_login = ?
WHERE id = ?
''', (datetime.now().isoformat(), user_id))
conn.commit()
log_login_attempt(user_id, True)
conn.close()
print("登录成功!")
return user_id
# 记录登录尝试
def log_login_attempt(user_id, success):
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
# 获取客户端IP地址(简化版)
try:
import socket
hostname = socket.gethostname()
ip_address = socket.gethostbyname(hostname)
except:
ip_address = "127.0.0.1"
cursor.execute('''
INSERT INTO login_logs (user_id, timestamp, ip_address, success)
VALUES (?, ?, ?, ?)
''', (user_id, datetime.now().isoformat(), ip_address, 1 if success else 0))
conn.commit()
conn.close()
# 主菜单
def main_menu():
init_db()
while True:
print("\n" + "="*50)
print("Python OPT认证系统")
print("="*50)
print("1. 注册新用户")
print("2. 登录")
print("3. 退出系统")
choice = input("请选择操作: ").strip()
if choice == "1":
register_user()
elif choice == "2":
user_id = login_user()
if user_id:
# 登录成功后的操作
print(f"\n欢迎回来,用户ID: {user_id}")
input("按Enter键返回主菜单...")
elif choice == "3":
print("感谢使用,再见!")
break
else:
print("无效的选择,请重新输入。")
if __name__ == "__main__":
main_menu()
系统功能说明
-
数据库设计:
- 用户表存储用户名、密码哈希、TOTP密钥、登录失败次数和锁定时间
- 登录日志表记录每次登录尝试的时间、IP和结果
-
安全特性:
- 密码使用SHA-256哈希存储
- 多次登录失败后账户自动锁定
- 完整的登录审计日志
- OPT恢复密钥在注册时显示
-
OPT特性:
- 使用pyotp库实现TOTP(基于时间的一次性密码)
- 生成二维码方便用户添加到认证器应用
- 30秒自动更新的动态验证码
-
用户体验:
- 清晰的命令行界面
- 密码输入隐藏
- 账户锁定倒计时显示
- 登录尝试次数提示
使用说明
- 首次运行会自动创建数据库
- 注册新用户时会生成OPT密钥并显示二维码
- 使用Google Authenticator等应用扫描二维码添加账户
- 登录时需要提供用户名、密码和OPT验证码
依赖安装
pip install pyotp qrcode sqlite3
安全建议
- 在生产环境中使用更强大的数据库(如PostgreSQL或MySQL)
- 对敏感数据(如TOTP密钥)进行加密存储
- 增加密码强度要求
- 实现IP地址访问限制
- 添加多因素认证恢复机制
这个实现提供了一个完整的OPT认证系统基础,可以根据实际需求进行扩展和增强。