3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

農工大Advent Calendar 2024

Day 25

【煩悩】大晦日1日でゲーム作って年内に滑り込みチャレンジ2024【前編】

Last updated at Posted at 2024-12-31

はじめに

大晦日の1日だけでゲームを作ってQiitaに記事を投稿できるかチャレンジ。

大晦日といえば、108つのアレですよね。

そうです。煩悩 です。

ということで(?)煩悩をぶっ壊す便利ツール「煩悩デストラクター」を作りました!!!

こちらから遊ぶことができます。遊んでみてね。
http://delphy8.s324.xrea.com/index.html

@Kumanoku@Delphyilia の合作になります!

早速ゲームを作っていきます!と言いたいところですが、【前編】ではログイン機能を作ります。

ゲーム部分の記事を読みたい!という方は @Delphyilia の【後編】をこちらからどうぞ↓

ログイン機能の実装(Kumanoku担当)

概要

PythonのCGIを使用して、ログイン(ユーザー登録とユーザー認証)の機能を実装します。
以下の2つのCGIを作成します。

  • ユーザー登録用CGI(register.cgi)
    1. ユーザー名とパスワードの入力フォーム
    2. パスワードをSHA256でハッシュ化
    3. ユーザー名とハッシュ化パスワードをcsvに保存
  • ユーザー認証用CGI(login.cgi)
    1. ユーザー名とパスワードの入力フォーム
    2. パスワードをSHA256でハッシュ化
    3. csvに保存されたユーザー名・パスワードと照合

環境

PythonのCGIが動作するWebサーバーを用意します。今回は無料のレンタルサーバーであるXREAを利用します。

XREAのPythonの実行パスは/usr/bin/python3.6です。詳しいサーバー仕様は以下のXREAのページを参照してください。

ユーザー登録用CGI

register.cgi
#!/usr/bin/python3.6

import cgi
import hashlib
import csv
import os

DATA_FILE = "users.csv"

# ハッシュ化関数
def hash_password(password):
    return hashlib.sha256(password.encode()).hexdigest()

# 既存のユーザー名か?
def user_exists(username):
    if not os.path.exists(DATA_FILE):
        return False
    with open(DATA_FILE, "r") as f:
        reader = csv.reader(f)
        for row in reader:
            if row[0] == username:
                return True
    return False

# csvに保存
def register_user(username, password):
    hashed_password = hash_password(password)
    with open(DATA_FILE, "a", newline="") as f:
        writer = csv.writer(f)
        writer.writerow([username, hashed_password])

# ヘッダーの設定
print("Content-Type: text/html; charset=utf-8\n\n")

form = cgi.FieldStorage()
username = form.getvalue("username")
password = form.getvalue("password")
confirm_password = form.getvalue("confirm_password")

if username and password and confirm_password:
    if password != confirm_password:
        message = "パスワードが一致しません。"
    elif user_exists(username):
        message = "このユーザー名は既に登録されています。"
    else:
        register_user(username, password)
        message = "登録が完了しました。ログインページに戻ってログインしてください。"
else:
    message = "すべてのフィールドを入力してください。"

print(f"""
<html>
<head><title>ユーザー登録</title></head>
<body>
<h1>ユーザー登録</h1>
<form method="post" action="register.cgi">
    <label for="username">ユーザー名: </label><input type="text" id="username" name="username" required><br>
    <label for="password">パスワード: </label><input type="password" id="password" name="password" required><br>
    パスワード確認: <input type="password" name="confirm_password" required><br>
    <input type="submit" value="登録">
</form>
<p>{message}</p>
<p><a href="login.cgi">ログインページに戻る</a></p>
</body>
</html>
""")

ユーザー名が被らないように、入力されたユーザー名がcsvに既存であれば弾くようにしています。

実行すると以下のような表示になります。

image.png

すべてのフィールドを入力して「登録」を押すと...

image.png

登録できました。

ユーザー認証用CGI

login.cgi
#!/usr/bin/python3.6

import cgi 
import hashlib 
import csv 
import os

DATA_FILE = "users.csv" 

# ハッシュ化関数
def hash_password(password): 
    return hashlib.sha256(password.encode()).hexdigest() 

# ユーザ認証関数
def authenticate_user(username, password): 
    hashed_password = hash_password(password) 
    if not os.path.exists(DATA_FILE):
        return False 
    with open(DATA_FILE, "r") as f: 
        reader = csv.reader(f) 
        for row in reader: 
            if row[0] == username and row[1] == hashed_password: 
                return True 
    return False 

# ヘッダーの設定
print("Content-Type: text/html; charset=utf-8\n\n") 

form = cgi.FieldStorage() 
username = form.getvalue("username") 
password = form.getvalue("password") 

if username and password: 
    if authenticate_user(username, password): 
        message = "ログイン成功!" 
    else: 
        message = "ユーザ名またはパスワードが間違っています。" 
else: 
    message = "ユーザ名とパスワードを入力してください" 

print(f"""
<html lang="ja">
<head><title>ログイン</title></head>
<body>
<h1>ログイン</h1>
<form method="post" action="login.cgi">
    <label for="username">ユーザー名: </label><input type="text" id="username" name="username" required><br>
    <label for="password">パスワード: </label><input type="password" id="password" name="password" required><br>
    <input type="submit" value="ログイン">
</form>
<p>{message}</p>
<p><a href="register.cgi">新規登録はこちら</a></p>
</body>
</html>
""")

実行すると以下のような表示になります。

image.png

先ほど登録した内容を入力して「ログイン」を押すと...

image.png

ログイン成功しました!

余談

Microsoft Edgeで開くと、

image.png

このようにパスワードのフォームに目のアイコン(パスワード表示ボタン)が表示されます。

これを削除したい場合は

::-ms-reveal {
    display: none;
}

このようにアイコンのスタイルに手を加えれば良いです。

詳しくは以下を参照↓

おわりに

これが初めてのQiita投稿、初めての共同作業()です。

ゲーム本体を作ったのに私の名義で投稿するよう勧めてくれた友人の @Delphyilia 君、ありがとう。

バックエンドへの理解が浅く、Pythonで何となく書けるCGIしか手を出せていないのが現状です。
REST API?WebSocket?右も左も分からないので勉強していきたいです。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?