feat(auth): refresh token 先 Redis 后 MySQL 双写
登录 30 天会话 hash 持久化到 admin_refresh_tokens;启动从 MySQL 回填 Redis, Redis 重启后会话仍可 refresh。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+9
-8
@@ -277,8 +277,9 @@ async def change_password(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Change the current admin's password (requires current password verification)"""
|
||||
from server.infrastructure.database.admin_repo import AdminRepositoryImpl
|
||||
from server.infrastructure.database.admin_repo import AdminRepositoryImpl, LoginAttemptRepositoryImpl
|
||||
from server.infrastructure.database.audit_log_repo import AuditLogRepositoryImpl
|
||||
from server.infrastructure.database.refresh_token_repo import RefreshTokenRepositoryImpl
|
||||
|
||||
admin_repo = AdminRepositoryImpl(db)
|
||||
current_admin = await admin_repo.get_by_id(admin.id)
|
||||
@@ -305,13 +306,13 @@ async def change_password(
|
||||
current_admin.token_version = (current_admin.token_version or 0) + 1
|
||||
await admin_repo.update(current_admin)
|
||||
|
||||
# Clear all refresh tokens from Redis (all devices logged out)
|
||||
try:
|
||||
from server.infrastructure.redis.client import get_redis
|
||||
redis = get_redis()
|
||||
await redis.delete(f"refresh_tokens:{admin.id}")
|
||||
except Exception:
|
||||
logger.warning(f"Failed to clear refresh tokens from Redis for admin {admin.id}", exc_info=True)
|
||||
auth_service = AuthService(
|
||||
admin_repo=admin_repo,
|
||||
attempt_repo=LoginAttemptRepositoryImpl(db),
|
||||
audit_repo=audit_repo,
|
||||
refresh_token_repo=RefreshTokenRepositoryImpl(db),
|
||||
)
|
||||
await auth_service._delete_all_refresh_tokens(admin.id)
|
||||
|
||||
# Audit log with client IP
|
||||
ip_address = get_client_ip(request)
|
||||
|
||||
Reference in New Issue
Block a user