Spaces:
Running
Running
Upload router_users.py
Browse files- router_users.py +25 -15
router_users.py
CHANGED
|
@@ -161,13 +161,28 @@ async def send_verify_code(req: SendCodeRequest, bg_tasks: BackgroundTasks):
|
|
| 161 |
|
| 162 |
return {"status": "success", "message": "验证码发送请求已提交"}
|
| 163 |
|
|
|
|
| 164 |
@router.post("/api/users/register")
|
| 165 |
async def register_user(user: UserRegister):
|
| 166 |
users_db = db.load_data("users.json", default_data={})
|
| 167 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
cache_key = f"{user.email}_register" if user.email else f"{user.phone}_register"
|
| 169 |
cached = VERIFY_CODES.get(cache_key)
|
| 170 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
raise HTTPException(status_code=400, detail="验证码不正确或已过期")
|
| 172 |
|
| 173 |
if len(user.account) <= 5: raise HTTPException(status_code=400, detail="账号必须大于5个字符")
|
|
@@ -175,10 +190,6 @@ async def register_user(user: UserRegister):
|
|
| 175 |
if len(user.password) < 6: raise HTTPException(status_code=400, detail="密码必须大于等于6个字符")
|
| 176 |
if not re.match(r'^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};\':"\\|,.<>\/?]{6,}$', user.password): raise HTTPException(status_code=400, detail="密码包含不支持的特殊字符")
|
| 177 |
if user.intro and len(user.intro) > 100: raise HTTPException(status_code=400, detail="个人介绍不能超过100个字符")
|
| 178 |
-
if user.account in users_db: raise HTTPException(status_code=400, detail="该账号已被注册")
|
| 179 |
-
for existing_user in users_db.values():
|
| 180 |
-
if user.email and existing_user.get("email") == user.email: raise HTTPException(status_code=400, detail="该邮箱已被绑定")
|
| 181 |
-
if user.phone and existing_user.get("phone") == user.phone: raise HTTPException(status_code=400, detail="该手机号已被绑定")
|
| 182 |
|
| 183 |
VERIFY_CODES.pop(cache_key, None)
|
| 184 |
|
|
@@ -189,6 +200,7 @@ async def register_user(user: UserRegister):
|
|
| 189 |
db.save_data("users.json", users_db)
|
| 190 |
return {"status": "success", "message": "注册成功", "data": {k: v for k, v in new_user.items() if k != "password"}}
|
| 191 |
|
|
|
|
| 192 |
@router.post("/api/users/login")
|
| 193 |
async def login_user(user: UserLogin):
|
| 194 |
users_db = db.load_data("users.json", default_data={})
|
|
@@ -197,40 +209,35 @@ async def login_user(user: UserLogin):
|
|
| 197 |
if user_data.get("password") != user.password: raise HTTPException(status_code=401, detail="密码错误")
|
| 198 |
return {"status": "success", "token": f"mock_token_{user.account}", "account": user.account, "name": user_data["name"], "avatar": user_data.get("avatarDataUrl", "https://via.placeholder.com/150")}
|
| 199 |
|
|
|
|
| 200 |
# ==========================================
|
| 201 |
# 补充:发送验证码的 API 接口
|
| 202 |
# ==========================================
|
| 203 |
@router.post("/api/users/send_code")
|
| 204 |
async def send_code_api(req: SendCodeRequest):
|
| 205 |
-
# 1. 生成 6 位随机数字验证码
|
| 206 |
code = str(random.randint(100000, 999999))
|
| 207 |
-
|
| 208 |
-
# 2. 生成缓存 Key (格式: 邮箱地址_动作)
|
| 209 |
-
# 例如: test@qq.com_register 或 test@qq.com_reset
|
| 210 |
key = f"{req.contact}_{req.action_type}"
|
| 211 |
|
| 212 |
-
# 3
|
| 213 |
VERIFY_CODES[key] = {
|
| 214 |
"code": code,
|
| 215 |
-
"
|
| 216 |
}
|
| 217 |
|
| 218 |
-
# 4. 触发发送逻辑
|
| 219 |
if req.contact_type == "email":
|
| 220 |
try:
|
| 221 |
-
# 调用你文件里已经写好的通过 Make.com Webhook 发邮件的函数
|
| 222 |
send_email_code(req.contact, code, req.action_type)
|
| 223 |
return {"status": "success", "message": "验证码已成功发送至邮箱"}
|
| 224 |
except Exception as e:
|
| 225 |
raise HTTPException(status_code=500, detail=f"邮件发送失败: {str(e)}")
|
| 226 |
|
| 227 |
elif req.contact_type == "phone":
|
| 228 |
-
# 预留的短信通道
|
| 229 |
return {"status": "success", "message": "验证码已成功发送至手机"}
|
| 230 |
|
| 231 |
else:
|
| 232 |
raise HTTPException(status_code=400, detail="不支持的验证方式")
|
| 233 |
|
|
|
|
| 234 |
@router.get("/api/users/{account}")
|
| 235 |
async def get_user_profile(account: str):
|
| 236 |
users_db = db.load_data("users.json", default_data={})
|
|
@@ -267,7 +274,10 @@ async def reset_password(account: str, pwd_data: PasswordReset):
|
|
| 267 |
|
| 268 |
cache_key = f"{pwd_data.verify_contact}_reset"
|
| 269 |
cached = VERIFY_CODES.get(cache_key)
|
| 270 |
-
|
|
|
|
|
|
|
|
|
|
| 271 |
raise HTTPException(status_code=400, detail="验证码不正确或已过期")
|
| 272 |
|
| 273 |
if len(pwd_data.new_password) < 6: raise HTTPException(status_code=400, detail="新密码必须大于等于6个字符")
|
|
|
|
| 161 |
|
| 162 |
return {"status": "success", "message": "验证码发送请求已提交"}
|
| 163 |
|
| 164 |
+
|
| 165 |
@router.post("/api/users/register")
|
| 166 |
async def register_user(user: UserRegister):
|
| 167 |
users_db = db.load_data("users.json", default_data={})
|
| 168 |
|
| 169 |
+
# 🚀 核心修复 1:将查重逻辑移到最前面!一旦重复直接拦截,绝不会发生 500 崩溃
|
| 170 |
+
if user.account in users_db:
|
| 171 |
+
raise HTTPException(status_code=400, detail="该账号已被注册,请更换一个")
|
| 172 |
+
for existing_user in users_db.values():
|
| 173 |
+
if user.email and existing_user.get("email") == user.email:
|
| 174 |
+
raise HTTPException(status_code=400, detail="此邮箱已注册,请直接登录或找回密码")
|
| 175 |
+
if user.phone and existing_user.get("phone") == user.phone:
|
| 176 |
+
raise HTTPException(status_code=400, detail="该手机号已被绑定")
|
| 177 |
+
|
| 178 |
+
# 获取验证码缓存记录
|
| 179 |
cache_key = f"{user.email}_register" if user.email else f"{user.phone}_register"
|
| 180 |
cached = VERIFY_CODES.get(cache_key)
|
| 181 |
+
|
| 182 |
+
# 🚀 核心修复 2:安全地获取过期时间,兼容新老写法,彻底消灭 KeyError 导致的 500
|
| 183 |
+
expire_time = cached.get("expires_at", cached.get("expires", 0)) if cached else 0
|
| 184 |
+
|
| 185 |
+
if not cached or cached["code"] != user.code or time.time() > expire_time:
|
| 186 |
raise HTTPException(status_code=400, detail="验证码不正确或已过期")
|
| 187 |
|
| 188 |
if len(user.account) <= 5: raise HTTPException(status_code=400, detail="账号必须大于5个字符")
|
|
|
|
| 190 |
if len(user.password) < 6: raise HTTPException(status_code=400, detail="密码必须大于等于6个字符")
|
| 191 |
if not re.match(r'^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};\':"\\|,.<>\/?]{6,}$', user.password): raise HTTPException(status_code=400, detail="密码包含不支持的特殊字符")
|
| 192 |
if user.intro and len(user.intro) > 100: raise HTTPException(status_code=400, detail="个人介绍不能超过100个字符")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 193 |
|
| 194 |
VERIFY_CODES.pop(cache_key, None)
|
| 195 |
|
|
|
|
| 200 |
db.save_data("users.json", users_db)
|
| 201 |
return {"status": "success", "message": "注册成功", "data": {k: v for k, v in new_user.items() if k != "password"}}
|
| 202 |
|
| 203 |
+
|
| 204 |
@router.post("/api/users/login")
|
| 205 |
async def login_user(user: UserLogin):
|
| 206 |
users_db = db.load_data("users.json", default_data={})
|
|
|
|
| 209 |
if user_data.get("password") != user.password: raise HTTPException(status_code=401, detail="密码错误")
|
| 210 |
return {"status": "success", "token": f"mock_token_{user.account}", "account": user.account, "name": user_data["name"], "avatar": user_data.get("avatarDataUrl", "https://via.placeholder.com/150")}
|
| 211 |
|
| 212 |
+
|
| 213 |
# ==========================================
|
| 214 |
# 补充:发送验证码的 API 接口
|
| 215 |
# ==========================================
|
| 216 |
@router.post("/api/users/send_code")
|
| 217 |
async def send_code_api(req: SendCodeRequest):
|
|
|
|
| 218 |
code = str(random.randint(100000, 999999))
|
|
|
|
|
|
|
|
|
|
| 219 |
key = f"{req.contact}_{req.action_type}"
|
| 220 |
|
| 221 |
+
# 🚀 核心修复 3:统一改成 expires_at,与全局校验逻辑完美对齐
|
| 222 |
VERIFY_CODES[key] = {
|
| 223 |
"code": code,
|
| 224 |
+
"expires_at": time.time() + 600
|
| 225 |
}
|
| 226 |
|
|
|
|
| 227 |
if req.contact_type == "email":
|
| 228 |
try:
|
|
|
|
| 229 |
send_email_code(req.contact, code, req.action_type)
|
| 230 |
return {"status": "success", "message": "验证码已成功发送至邮箱"}
|
| 231 |
except Exception as e:
|
| 232 |
raise HTTPException(status_code=500, detail=f"邮件发送失败: {str(e)}")
|
| 233 |
|
| 234 |
elif req.contact_type == "phone":
|
|
|
|
| 235 |
return {"status": "success", "message": "验证码已成功发送至手机"}
|
| 236 |
|
| 237 |
else:
|
| 238 |
raise HTTPException(status_code=400, detail="不支持的验证方式")
|
| 239 |
|
| 240 |
+
|
| 241 |
@router.get("/api/users/{account}")
|
| 242 |
async def get_user_profile(account: str):
|
| 243 |
users_db = db.load_data("users.json", default_data={})
|
|
|
|
| 274 |
|
| 275 |
cache_key = f"{pwd_data.verify_contact}_reset"
|
| 276 |
cached = VERIFY_CODES.get(cache_key)
|
| 277 |
+
|
| 278 |
+
# 这里同样加上安全获取策略防崩
|
| 279 |
+
expire_time = cached.get("expires_at", cached.get("expires", 0)) if cached else 0
|
| 280 |
+
if not cached or cached["code"] != pwd_data.code or time.time() > expire_time:
|
| 281 |
raise HTTPException(status_code=400, detail="验证码不正确或已过期")
|
| 282 |
|
| 283 |
if len(pwd_data.new_password) < 6: raise HTTPException(status_code=400, detail="新密码必须大于等于6个字符")
|