修正
This commit is contained in:
@@ -2,9 +2,11 @@ from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import JSONResponse, RedirectResponse
|
||||
from fastapi.responses import JSONResponse, RedirectResponse, Response
|
||||
from pydantic import ValidationError
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from starlette.datastructures import MutableHeaders
|
||||
from starlette.types import ASGIApp, Receive, Scope, Send
|
||||
|
||||
# FastAPI アプリケーション作成
|
||||
app = FastAPI(
|
||||
@@ -12,13 +14,37 @@ app = FastAPI(
|
||||
)
|
||||
|
||||
|
||||
class SecurityHeadersMiddleware:
|
||||
"""キャッシュ禁止・セキュリティヘッダーを全レスポンスに付与(ASGIネイティブ実装)”"""
|
||||
def __init__(self, app: ASGIApp) -> None:
|
||||
self.app = app
|
||||
|
||||
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
||||
if scope["type"] != "http":
|
||||
await self.app(scope, receive, send)
|
||||
return
|
||||
|
||||
async def send_with_headers(message):
|
||||
if message["type"] == "http.response.start":
|
||||
headers = MutableHeaders(scope=message)
|
||||
headers["Cache-Control"] = "no-store, no-cache, must-revalidate, private"
|
||||
headers["Pragma"] = "no-cache"
|
||||
headers["Expires"] = "0"
|
||||
headers["X-Frame-Options"] = "DENY"
|
||||
headers["X-Content-Type-Options"] = "nosniff"
|
||||
headers["X-XSS-Protection"] = "1; mode=block"
|
||||
await send(message)
|
||||
|
||||
await self.app(scope, receive, send_with_headers)
|
||||
|
||||
app.add_middleware(SecurityHeadersMiddleware)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=False,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
||||
allow_headers=["Content-Type", "Authorization"],
|
||||
)
|
||||
|
||||
# ─────────────────────────
|
||||
|
||||
@@ -12,6 +12,12 @@ class LoginRequest(BaseModel):
|
||||
password: str
|
||||
|
||||
|
||||
class ChangePasswordRequest(BaseModel):
|
||||
username: str
|
||||
current_password: str
|
||||
new_password: str
|
||||
|
||||
|
||||
class LoginResponse(BaseModel):
|
||||
id: int
|
||||
username: str
|
||||
@@ -66,39 +72,48 @@ async def login(request: LoginRequest):
|
||||
|
||||
@router.post("/register")
|
||||
async def register(request: LoginRequest):
|
||||
"""新規ユーザー登録"""
|
||||
"""新規ユーザー登録(無効化済み)"""
|
||||
raise HTTPException(status_code=403, detail="新規ユーザー登録は現在受け付けていません")
|
||||
|
||||
|
||||
@router.post("/change-password")
|
||||
async def change_password(request: ChangePasswordRequest):
|
||||
"""パスワード変更"""
|
||||
if len(request.new_password) < 8:
|
||||
raise HTTPException(status_code=400, detail="新しいパスワードは8文字以上である必要があります")
|
||||
|
||||
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.execute(
|
||||
"SELECT id, password FROM users WHERE username = %s AND is_active = TRUE",
|
||||
(request.username,)
|
||||
)
|
||||
user = cur.fetchone()
|
||||
|
||||
if not user:
|
||||
cur.close()
|
||||
conn.close()
|
||||
raise HTTPException(status_code=400, detail="このユーザー名は既に使用されています")
|
||||
|
||||
# ユーザーを登録
|
||||
hashed_password = hash_password(request.password)
|
||||
raise HTTPException(status_code=401, detail="ユーザーが見つかりません")
|
||||
|
||||
if user["password"] != hash_password(request.current_password):
|
||||
cur.close()
|
||||
conn.close()
|
||||
raise HTTPException(status_code=401, detail="現在のパスワードが正しくありません")
|
||||
|
||||
new_hashed = hash_password(request.new_password)
|
||||
cur.execute(
|
||||
"INSERT INTO users (username, password) VALUES (%s, %s) RETURNING id, username",
|
||||
(request.username, hashed_password)
|
||||
"UPDATE users SET password = %s WHERE username = %s",
|
||||
(new_hashed, request.username)
|
||||
)
|
||||
new_user = cur.fetchone()
|
||||
conn.commit()
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
return {
|
||||
"id": new_user["id"],
|
||||
"username": new_user["username"],
|
||||
"message": "ユーザー登録が完了しました"
|
||||
}
|
||||
|
||||
|
||||
return {"message": "パスワードを変更しました"}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"登録処理エラー: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"パスワード変更エラー: {str(e)}")
|
||||
|
||||
Reference in New Issue
Block a user