Fix: Handle 'user_agent' data truncation error

This commit is contained in:
咕谷酱
2025-08-22 15:17:03 +08:00
parent e293d7541b
commit 3b1d7a2234
5 changed files with 128 additions and 4 deletions

View File

@@ -35,7 +35,7 @@ class LoginSession(SQLModel, table=True):
user_id: int = Field(sa_column=Column(BigInteger, ForeignKey("lazer_users.id"), nullable=False, index=True))
session_token: str = Field(unique=True, index=True) # 会话令牌
ip_address: str = Field() # 登录IP
user_agent: str | None = Field(default=None)
user_agent: str | None = Field(default=None, max_length=250)
country_code: str | None = Field(default=None)
is_verified: bool = Field(default=False) # 是否已验证
created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))

View File

@@ -388,13 +388,18 @@ class LoginSessionService:
is_new_location: bool = False
) -> LoginSession:
"""创建登录会话"""
from app.utils import simplify_user_agent
session_token = EmailVerificationService.generate_session_token()
# 简化 User-Agent 字符串
simplified_user_agent = simplify_user_agent(user_agent, max_length=250)
session = LoginSession(
user_id=user_id,
session_token=session_token,
ip_address=ip_address,
user_agent=user_agent,
user_agent=simplified_user_agent,
country_code=country_code,
is_new_location=is_new_location,
expires_at=datetime.now(UTC) + timedelta(hours=24), # 24小时过期

View File

@@ -45,8 +45,10 @@ class LoginLogService:
raw_ip = get_client_ip(request)
ip_address = normalize_ip(raw_ip)
# 获取User-Agent
user_agent = request.headers.get("User-Agent", "")
# 获取并简化User-Agent
from app.utils import simplify_user_agent
raw_user_agent = request.headers.get("User-Agent", "")
user_agent = simplify_user_agent(raw_user_agent, max_length=500)
# 创建基本的登录记录
login_log = UserLoginLog(

View File

@@ -146,3 +146,80 @@ def check_image(content: bytes, size: int, width: int, height: int) -> None:
)
except Exception as e:
raise HTTPException(status_code=400, detail=f"Error processing image: {e}")
def simplify_user_agent(user_agent: str | None, max_length: int = 200) -> str | None:
"""
简化 User-Agent 字符串,只保留 osu! 和关键设备系统信息浏览器
Args:
user_agent: 原始 User-Agent 字符串
max_length: 最大长度限制
Returns:
简化后的 User-Agent 字符串,或 None
"""
import re
if not user_agent:
return None
# 如果长度在限制内,直接返回
if len(user_agent) <= max_length:
return user_agent
# 提取操作系统信息
os_info = ""
os_patterns = [
r'(Windows[^;)]*)',
r'(Mac OS[^;)]*)',
r'(Linux[^;)]*)',
r'(Android[^;)]*)',
r'(iOS[^;)]*)',
r'(iPhone[^;)]*)',
r'(iPad[^;)]*)'
]
for pattern in os_patterns:
match = re.search(pattern, user_agent, re.IGNORECASE)
if match:
os_info = match.group(1).strip()
break
# 提取浏览器信息
browser_info = ""
browser_patterns = [
r'(osu![^)]*)', # osu! 客户端
r'(Chrome/[\d.]+)',
r'(Firefox/[\d.]+)',
r'(Safari/[\d.]+)',
r'(Edge/[\d.]+)',
r'(Opera/[\d.]+)'
]
for pattern in browser_patterns:
match = re.search(pattern, user_agent, re.IGNORECASE)
if match:
browser_info = match.group(1).strip()
# 如果找到了 osu! 客户端,优先使用
if 'osu!' in browser_info.lower():
break
# 构建简化的 User-Agent
parts = []
if os_info:
parts.append(os_info)
if browser_info:
parts.append(browser_info)
if parts:
simplified = '; '.join(parts)
else:
# 如果没有识别到关键信息,截断原始字符串
simplified = user_agent[:max_length-3] + "..."
# 确保不超过最大长度
if len(simplified) > max_length:
simplified = simplified[:max_length-3] + "..."
return simplified

View File

@@ -0,0 +1,40 @@
"""Increase the length limit of the user_agent field in the login_sessions table
Revision ID: 5b76689f6e4b
Revises: 65e7dc8d5905
Create Date: 2025-08-22 15:14:59.242274
"""
from __future__ import annotations
from collections.abc import Sequence
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision: str = "5b76689f6e4b"
down_revision: str | Sequence[str] | None = "65e7dc8d5905"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column("login_sessions", "user_agent",
existing_type=mysql.VARCHAR(length=255),
type_=sa.String(length=250),
existing_nullable=True)
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column("login_sessions", "user_agent",
existing_type=sa.String(length=250),
type_=mysql.VARCHAR(length=255),
existing_nullable=True)
# ### end Alembic commands ###