見出し画像

【100個デスクトップアプリ作成】44個目:パスワードを3回間違えるとロックアウトするプログラム

以前ユーザーごとに権限をつけて、見れる画面を切り替えるものを作りました。

今回はWebではよくやるパスワードを3回間違えると、ロックアウトしてしまうプログラムを作ります。

当然パスワードは外部に覚えさせる必要があるので、JSONファイルを活用します。

それではChatGPTの司令です。

以前作った権限によって画面を変えるプログラムを作りましたが、パスワードを3回連続で間違えるとロックアウト(2度とログインできない)機能を追加したい。 ソースコードを教えてほしい。

ChatGPTへの司令

できたソースコードが以下です。

import tkinter as tk
from tkinter import messagebox, ttk
import json
import os
import re

USER_FILE = "users.json"

class UserApp:
    def __init__(self, root):
        self.root = root
        self.root.title("ユーザーアプリ")
        self.users = self.load_users()
        self.show_register_screen()

    def load_users(self):
        if os.path.exists(USER_FILE):
            with open(USER_FILE, "r", encoding="utf-8") as f:
                return json.load(f)
        return {}

    def save_users(self):
        with open(USER_FILE, "w", encoding="utf-8") as f:
            json.dump(self.users, f, indent=2, ensure_ascii=False)

    def clear_screen(self):
        for widget in self.root.winfo_children():
            widget.destroy()

    def show_register_screen(self):
        self.clear_screen()

        tk.Label(self.root, text="ユーザー登録", font=("Arial", 14)).pack(pady=10)

        tk.Label(self.root, text="ユーザー名(英字のみ)").pack()
        self.username_var = tk.StringVar()
        tk.Entry(self.root, textvariable=self.username_var).pack()

        tk.Label(self.root, text="パスワード(英大小字・数字含む)").pack()
        self.password_var = tk.StringVar()
        tk.Entry(self.root, textvariable=self.password_var, show="*").pack()

        tk.Label(self.root, text="権限").pack()
        self.role_var = tk.StringVar()
        ttk.Combobox(self.root, textvariable=self.role_var, values=["管理者権限", "一般権限"], state="readonly").pack()

        tk.Button(self.root, text="登録", command=self.register_user).pack(pady=10)

    def register_user(self):
        username = self.username_var.get().strip()
        password = self.password_var.get()
        role = self.role_var.get()

        if not re.fullmatch(r"[A-Za-z]+", username):
            messagebox.showerror("エラー", "ユーザー名は英字のみです。")
            return

        if not re.search(r"[a-z]", password) or not re.search(r"[A-Z]", password) or not re.search(r"[0-9]", password):
            messagebox.showerror("エラー", "パスワードは英大文字・小文字・数字をすべて含む必要があります。")
            return

        if role not in ["管理者権限", "一般権限"]:
            messagebox.showerror("エラー", "権限を選択してください。")
            return

        if username in self.users:
            messagebox.showerror("エラー", "このユーザー名は既に登録されています。")
            return

        self.users[username] = {
            "password": password,
            "role": role,
            "locked": False,
            "fail_count": 0
        }
        self.save_users()

        messagebox.showinfo("完了", "ユーザー登録が完了しました。")
        self.show_login_screen()

    def show_login_screen(self):
        self.clear_screen()

        tk.Label(self.root, text="ログイン画面", font=("Arial", 14)).pack(pady=10)

        tk.Label(self.root, text="ユーザー名").pack()
        self.login_user_var = tk.StringVar()
        tk.Entry(self.root, textvariable=self.login_user_var).pack()

        tk.Label(self.root, text="パスワード").pack()
        self.login_pass_var = tk.StringVar()
        tk.Entry(self.root, textvariable=self.login_pass_var, show="*").pack()

        tk.Button(self.root, text="ログイン", command=self.login_user).pack(pady=10)

    def login_user(self):
        username = self.login_user_var.get().strip()
        password = self.login_pass_var.get()

        user = self.users.get(username)

        if not user:
            messagebox.showerror("ログイン失敗", "ユーザーが存在しません。")
            return

        if user.get("locked"):
            messagebox.showerror("ロック中", "このユーザーはロックされています。ログインできません。")
            return

        if user["password"] == password:
            user["fail_count"] = 0
            self.save_users()
            self.show_main_screen(user["role"], username)
        else:
            user["fail_count"] += 1
            if user["fail_count"] >= 3:
                user["locked"] = True
                messagebox.showerror("ロックアウト", "パスワードを3回間違えたため、アカウントがロックされました。")
            else:
                messagebox.showerror("ログイン失敗", f"パスワードが間違っています。残り試行回数: {3 - user['fail_count']}")
            self.save_users()

    def show_main_screen(self, role, username):
        self.clear_screen()
        msg = f"{username} さんは {role} です"
        tk.Label(self.root, text=msg, font=("Arial", 16, "bold")).pack(pady=20)

        color = "#ffdddd" if role == "管理者権限" else "#ddeeff"
        label = tk.Label(self.root, text=role, font=("Arial", 24), bg=color, width=20)
        label.pack(pady=20)

        tk.Button(self.root, text="終了", command=self.root.quit).pack(pady=10)

if __name__ == "__main__":
    root = tk.Tk()
    app = UserApp(root)
    root.mainloop()

以前のユーザー登録ではパスワードの設定ミスについて、何度でも失敗は可能でしたが、今回JSONに失敗回数と、そのフラグを設定項目として追加することで、ロックアウトを可能にしました。

画面は以下です。

ユーザー登録画面

ここまでは以前作った管理者権限と、一般権限を登録するアプリと同様です。

ここからユーザー登録をして、ログイン失敗をするとどうなるかを画面で確認します。

ログイン失敗画面

次に3回連続失敗すると、以下の画面が出てきます。

アカウントロック画面

ここで正しいパスワードを入れると、以下のようになりログインできません。

アカウントロック中画面

これを解除するにはJSONファイルを書き換えて、再設定する必要があります。

30年前によくやったシステムの基礎ですが、Pythonでやっているところが結構面白く、勉強になりました。

社会システムでよく使う方法と、便利ツールの学習という側面で考えると、結構100個は突破しそうな気がします。

是非生成AIのプログラムについて、ご意見、ご感想をコメント欄にお願いします!

動画は以下です。

※Blueskyを使っていますので、フォローお願いします。

今回はChatGPTを使って3回パスワードを間違えると、ロックアウトする仕組みを作りました。(tkinterアプリ44個目) 実生活でもありありの、パスワードミス数回でロックアウトするプログラムを作ってみました。 このプログラムはjsonファイルにユーザー情報が格納されていて、そちらを直せばすぐに使えるのですが、実運用はこの解除がかなり面倒くさくなっています。 社会システムの基礎中の基礎を学習しました。 #100個チャレンジ #tkinter #Python #ChatGPT #パスワード #ロックアウト

神経質やせ男 (@wwphilosophy.bsky.social) 2025-07-07T22:02:53.695Z


いいなと思ったら応援しよう!

shinkeishitsu_yaseo いつも記事を読んでいただいて、ありがとうございます。もし気に入っていただけたなら応援お願いします!いただいたチップは創作活動と寄付に使わせていただきます。m(_ _)m