login画面追加

This commit is contained in:
admin
2026-02-07 14:25:28 +09:00
parent 9d1ad5594d
commit 331953bb7f
22 changed files with 763 additions and 135 deletions

View File

@@ -6,7 +6,6 @@ from fastapi.responses import JSONResponse, RedirectResponse
from pydantic import ValidationError
from fastapi.middleware.cors import CORSMiddleware
# FastAPI アプリケーション作成
app = FastAPI(
title="日本小規模企業向け会計システム"
@@ -32,13 +31,15 @@ async def validation_exception_handler(request: Request, exc: ValidationError):
# ─────────────────────────
# ルート(稼働確認)
# ─────────────────────────
#@app.get("/", include_in_schema=False)
#def root():
# return RedirectResponse(url="/index.html")
@app.get("/", include_in_schema=False)
def root():
return RedirectResponse("/login.html")
# ─────────────────────────
# ルーター登録(※ 必ず app 定義の後)
# ─────────────────────────
from app.modules.users.router import router as users_router
app.include_router(users_router)
from app.modules.accounts.router import router as accounts_router
app.include_router(accounts_router)
@@ -139,7 +140,7 @@ print("Frontend path =", frontend_path)
if frontend_path.exists():
app.mount(
"/",
StaticFiles(directory=frontend_path, html=True),
StaticFiles(directory=frontend_path),
name="frontend",
)
else:

View File

@@ -0,0 +1 @@
# Users Module

View File

@@ -0,0 +1,104 @@
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
import hashlib
import os
from app.core.database import get_connection
router = APIRouter(prefix="/api/users", tags=["users"])
class LoginRequest(BaseModel):
username: str
password: str
class LoginResponse(BaseModel):
id: int
username: str
full_name: str | None
email: str | None
message: str
def hash_password(password: str) -> str:
"""パスワードをハッシュ化"""
# 実運用ではより安全なハッシュアルゴリズムを使用してください
return hashlib.sha256(password.encode()).hexdigest()
@router.post("/login", response_model=LoginResponse)
async def login(request: LoginRequest):
"""ユーザーのログイン処理"""
try:
conn = get_connection()
cur = conn.cursor()
# ユーザーが存在するか確認
cur.execute(
"SELECT id, username, password, full_name, email FROM users WHERE username = %s AND is_active = TRUE",
(request.username,)
)
user = cur.fetchone()
cur.close()
conn.close()
if not user:
raise HTTPException(status_code=401, detail="ユーザー名またはパスワードが正しくありません")
# パスワードの検証
hashed_password = hash_password(request.password)
if user["password"] != hashed_password:
raise HTTPException(status_code=401, detail="ユーザー名またはパスワードが正しくありません")
return LoginResponse(
id=user["id"],
username=user["username"],
full_name=user["full_name"],
email=user["email"],
message="ログインに成功しました"
)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=f"ログイン処理エラー: {str(e)}")
@router.post("/register")
async def register(request: LoginRequest):
"""新規ユーザー登録"""
try:
if len(request.password) < 6:
raise HTTPException(status_code=400, detail="パスワードは6文字以上である必要があります")
conn = get_connection()
cur = conn.cursor()
# ユーザーが既に存在するか確認
cur.execute("SELECT id FROM users WHERE username = %s", (request.username,))
if cur.fetchone():
cur.close()
conn.close()
raise HTTPException(status_code=400, detail="このユーザー名は既に使用されています")
# ユーザーを登録
hashed_password = hash_password(request.password)
cur.execute(
"INSERT INTO users (username, password) VALUES (%s, %s) RETURNING id, username",
(request.username, hashed_password)
)
new_user = cur.fetchone()
conn.commit()
cur.close()
conn.close()
return {
"id": new_user["id"],
"username": new_user["username"],
"message": "ユーザー登録が完了しました"
}
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=f"登録処理エラー: {str(e)}")

View File

@@ -0,0 +1,14 @@
-- ユーザーテーブル作成
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
full_name VARCHAR(100),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- ユーザーの一覧表示用インデックス
CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);