程式碼檢視器 – A-auth-sqlite3-v1.py

← 返回清單
# auth.py
# 教學用最小登入系統(Python + SQLite)
# 特點:
# - 只用一個 users 資料表(username 唯一、password 明碼)
# - 無 sessions、無防暴力破解
# - 內含:建表、註冊、登入、列出使用者

import sqlite3
from pathlib import Path

DB_PATH = Path(__file__).with_name("auth_demo.db")

DDL_USERS = """
CREATE TABLE IF NOT EXISTS users (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    username   TEXT    NOT NULL UNIQUE,
    password   TEXT    NOT NULL,
    created_at TEXT    NOT NULL DEFAULT (datetime('now'))
);
"""

def get_conn():
    conn = sqlite3.connect(DB_PATH)
    conn.execute("PRAGMA foreign_keys = ON;")
    return conn

def init_db():
    with get_conn() as conn:
        conn.execute(DDL_USERS)
    print("資料庫初始化完成(若不存在則建立 users 資料表)。")

def register_user(username: str, password: str) -> bool:
    """註冊新使用者(密碼明碼;教學用)"""
    try:
        with get_conn() as conn:
            conn.execute(
                "INSERT INTO users (username, password) VALUES (?, ?);",
                (username, password),
            )
        return True
    except sqlite3.IntegrityError:
        return False

def verify_login(username: str, password: str) -> bool:
    """一次性登入驗證(比對明碼;教學用)"""
    with get_conn() as conn:
        row = conn.execute(
            "SELECT password FROM users WHERE username = ?;",
            (username,),
        ).fetchone()
    if row is None:
        return False
    return password == row[0]

def list_users():
    """列出所有使用者(會顯示明碼密碼,僅供教學觀察!)"""
    with get_conn() as conn:
        rows = conn.execute(
            "SELECT id, username, password, created_at FROM users ORDER BY id;"
        ).fetchall()
    if not rows:
        print("(目前沒有使用者)")
        return
    print("\n=== 使用者清單(教學用,含明碼) ===")
    for rid, uname, pwd, ctime in rows:
        print(f"[{rid}] {uname:15s}  密碼: {pwd:10s}  建立時間: {ctime}")
    print("=================================\n")

def seed_demo_user():
    """建立一個示範帳號 admin/admin(若不存在)"""
    with get_conn() as conn:
        row = conn.execute("SELECT 1 FROM users WHERE username='admin';").fetchone()
        if row is None:
            conn.execute(
                "INSERT INTO users (username, password) VALUES (?, ?);",
                ("admin", "admin"),
            )
            print("已建立示範帳號:username=admin / password=admin")

def main_menu():
    while True:
        print("\n=== 簡易登入系統(教學用)===")
        print("1) 註冊帳號")
        print("2) 登入系統")
        print("3) 查詢帳號")
        print("0) 離開")
        choice = input("請選擇:").strip()

        if choice == "1":
            u = input("請輸入帳號:").strip()
            p = input("請輸入密碼:").strip()
            if not u or not p:
                print("帳號與密碼不可為空!")
                continue
            ok = register_user(u, p)
            print("註冊成功!" if ok else "帳號已存在,請改用其他帳號。")

        elif choice == "2":
            u = input("請輸入帳號:").strip()
            p = input("請輸入密碼:").strip()
            ok = verify_login(u, p)
            print("登入成功!" if ok else "登入失敗,帳號或密碼錯誤。")

        elif choice == "3":
            list_users()

        elif choice == "0":
            print("Bye ~")
            break
        else:
            print("請輸入有效選項。")

if __name__ == "__main__":
    init_db()
    seed_demo_user()   # 預設建立 admin/1234 帳號
    main_menu()