Python OPT认证系统(结合SQLite数据库)

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()

系统功能说明

  1. 数据库设计

    • 用户表存储用户名、密码哈希、TOTP密钥、登录失败次数和锁定时间
    • 登录日志表记录每次登录尝试的时间、IP和结果
  2. 安全特性

    • 密码使用SHA-256哈希存储
    • 多次登录失败后账户自动锁定
    • 完整的登录审计日志
    • OPT恢复密钥在注册时显示
  3. OPT特性

    • 使用pyotp库实现TOTP(基于时间的一次性密码)
    • 生成二维码方便用户添加到认证器应用
    • 30秒自动更新的动态验证码
  4. 用户体验

    • 清晰的命令行界面
    • 密码输入隐藏
    • 账户锁定倒计时显示
    • 登录尝试次数提示

使用说明

  1. 首次运行会自动创建数据库
  2. 注册新用户时会生成OPT密钥并显示二维码
  3. 使用Google Authenticator等应用扫描二维码添加账户
  4. 登录时需要提供用户名、密码和OPT验证码

依赖安装

pip install pyotp qrcode sqlite3

安全建议

  1. 在生产环境中使用更强大的数据库(如PostgreSQL或MySQL)
  2. 对敏感数据(如TOTP密钥)进行加密存储
  3. 增加密码强度要求
  4. 实现IP地址访问限制
  5. 添加多因素认证恢复机制

这个实现提供了一个完整的OPT认证系统基础,可以根据实际需求进行扩展和增强。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值