Files
root 3618323192 fix(security): P1/P2 审计修复 + JWT HttpOnly Cookie 双模认证 + 限流
- P0/P1 审计修复: 滑块验证码不再下发 x_position/成败即销毁 key、
  user-login 补失败计数+滑块门控、限流标识改 X-Real-IP、
  百度翻译 appkey 环境化、ChangeEmail/ChangePhone 补调 avalidate、
  logs/tasks.py Count(filter=Q) 修复、chat 收藏 SSRF 内网黑名单
- P1 #6/7: token_blacklist + ROTATE_REFRESH_TOKENS 开启,
  /user/token/refresh/ 挂载
- #2 JWT HttpOnly Cookie 双模认证: user/cookie_auth.py 种/清 Cookie,
  user/authentication.py CookieOrHeaderJWTAuthentication(Bearer 优先/_COOKIE 兜底),
  user/views/token.py CookieTokenRefreshView + UserLogoutAPIView(/user/logout/),
  create_standardized_response 自动对含 token 的响应种 Cookie,
  异步视图内 RefreshToken.for_user 全部 sync_to_async 包裹(修 SynchronousOnlyOperation 500),
  WS ChatConsumer 优先读 Cookie token
- P2 #11 限流: utils/rate_limit.py 固定窗口频控,
  shorturl 生成 匿名10次/分+登录60次/分, 邮箱验证码 同邮箱60s1次+同IP10次/10min,
  登录/注册验证码 错5次作废+成功即销毁防重放, 换绑邮箱/手机 同步落地,
  urls.py 补挂 shorturl 路由(此前 404)
2026-09-08 11:28:00 +08:00

109 lines
7.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.urls import path
from .views.user import SendUserEmailAPIView, UserLoginOrRegisterAPIView, UserLoginAPIView, LoginView, ChangePasswordAPIView, UserUpdateAPIView, ForgotPasswordSendCodeAPIView, ForgotPasswordResetAPIView, UploadAvatarAPIView, PublicProfileAPIView
from .views.qr_login import QRTokenView, QRStatusView, QRScanView, QRConfirmView, QRCancelView
from .views.wallet import (
WalletBalanceAPIView,
WalletTransactionsAPIView,
EarnPointsAPIView,
EarnCoinsAPIView,
SpendPointsAPIView,
SpendCoinsAPIView,
CheckinStatusAPIView,
CheckinAPIView,
)
from .views.tasks import (
TaskListAPIView, TaskTrackAPIView, TaskClaimAPIView, UserLevelAPIView,
)
from .views.email import SendChangeEmailCodeAPIView, ChangeEmailAPIView
from .views.phone import SendPhoneCodeAPIView, ChangePhoneAPIView
from .views.favorites import MyFavoritesView, FavoriteToggleView
from .views.token import CookieTokenRefreshView, UserLogoutAPIView
from .views.captcha import CaptchaAPIView
from .views.slider_captcha import SliderCaptchaGenerateView, SliderCaptchaVerifyView
from .views.blacklist import BlacklistListAPIView, BlacklistAddAPIView, BlacklistRemoveAPIView, BlacklistCheckAPIView
from .views.login_record import LoginRecordListAPIView, LoginRecordDeleteAPIView, LoginRecordClearAPIView
from .views.invitation import InviteCodeAPIView, InviteStatsAPIView, InviteRecordsAPIView
from .views.user import FollowToggleView
from .views.favorites import MyFavoritesView
from .views.region import RegionListView
from .views.activities import UserActivityView
from .views.settings import (
UploadCoverAPIView,
PrivacySettingsAPIView,
NotificationSettingsAPIView,
UserDeviceListView,
UserDeviceRemoveView,
UserDeviceClearOthersView,
)
from .views.index import user_index
urlpatterns = [
path('', user_index, name='user_index'),
path('send-user-email/', SendUserEmailAPIView.as_view(), name='send_user_email'),
path('send_user_email/', SendUserEmailAPIView.as_view(), name='send_user_email_old'),
path('login-register/', UserLoginOrRegisterAPIView.as_view(), name='user_login_register'),
path('user_login_or_register/', UserLoginOrRegisterAPIView.as_view(), name='user_login_register_old'),
path('user-login/', UserLoginAPIView.as_view(), name='user_login'),
path('user_login/', UserLoginAPIView.as_view(), name='user_login_old'),
path('login/', LoginView.as_view(), name='login_with_slider'),
path('change-password/', ChangePasswordAPIView.as_view(), name='change_password'),
path('change_password/', ChangePasswordAPIView.as_view(), name='change_password_old'),
path('profile/', UserUpdateAPIView.as_view(), name='user_profile'),
path('update-profile/', UserUpdateAPIView.as_view(), name='user_update_profile'),
path('wallet/balance/', WalletBalanceAPIView.as_view(), name='wallet_balance'),
path('wallet/transactions/', WalletTransactionsAPIView.as_view(), name='wallet_transactions'),
path('wallet/earn/points/', EarnPointsAPIView.as_view(), name='wallet_earn_points'),
path('wallet/earn/coins/', EarnCoinsAPIView.as_view(), name='wallet_earn_coins'),
path('wallet/spend/points/', SpendPointsAPIView.as_view(), name='wallet_spend_points'),
path('wallet/spend/coins/', SpendCoinsAPIView.as_view(), name='wallet_spend_coins'),
path('wallet/checkin/status/', CheckinStatusAPIView.as_view(), name='wallet_checkin_status'),
path('wallet/checkin/', CheckinAPIView.as_view(), name='wallet_checkin'),
path('send-email-code/', SendChangeEmailCodeAPIView.as_view(), name='send_email_code'),
path('change-email/', ChangeEmailAPIView.as_view(), name='change_email'),
path('forgot-password/send-code/', ForgotPasswordSendCodeAPIView.as_view(), name='forgot_password_send_code'),
path('forgot-password/reset/', ForgotPasswordResetAPIView.as_view(), name='forgot_password_reset'),
path('send-phone-code/', SendPhoneCodeAPIView.as_view(), name='send_phone_code'),
path('change-phone/', ChangePhoneAPIView.as_view(), name='change_phone'),
path('captcha/', CaptchaAPIView.as_view(), name='captcha'),
path('slider-captcha/generate/', SliderCaptchaGenerateView.as_view(), name='slider-captcha-generate'),
path('slider-captcha/verify/', SliderCaptchaVerifyView.as_view(), name='slider-captcha-verify'),
path('upload-avatar/', UploadAvatarAPIView.as_view(), name='upload_avatar'),
path('blacklist/', BlacklistListAPIView.as_view(), name='blacklist'),
path('blacklist/add/', BlacklistAddAPIView.as_view(), name='blacklist_add'),
path('blacklist/<int:pk>/remove/', BlacklistRemoveAPIView.as_view(), name='blacklist_remove'),
path('blacklist/check/<int:user_id>/', BlacklistCheckAPIView.as_view(), name='blacklist_check'),
path('login-records/', LoginRecordListAPIView.as_view(), name='login_records'),
path('login-records/<int:pk>/delete/', LoginRecordDeleteAPIView.as_view(), name='login_record_delete'),
path('login-records/clear/', LoginRecordClearAPIView.as_view(), name='login_records_clear'),
path('public-profile/<int:user_id>/', PublicProfileAPIView.as_view(), name='public_profile'),
path('invite/code/', InviteCodeAPIView.as_view(), name='invite_code'),
path('invite/stats/', InviteStatsAPIView.as_view(), name='invite_stats'),
path('invite/records/', InviteRecordsAPIView.as_view(), name='invite_records'),
path('tasks/', TaskListAPIView.as_view(), name='task_list'),
path('tasks/track/', TaskTrackAPIView.as_view(), name='task_track'),
path('tasks/claim/<int:task_id>/', TaskClaimAPIView.as_view(), name='task_claim'),
path('level/', UserLevelAPIView.as_view(), name='user_level'),
path('favorites/', MyFavoritesView.as_view(), name='my_favorites'),
# 修复:新增统一收藏切换端点(Android FavoritesApi.toggleFavorite 依赖此路由)
path('favorites/toggle/', FavoriteToggleView.as_view(), name='my_favorites_toggle'),
# 修复:挂载 JWT 刷新端点(支持 HttpOnly Cookie 与 Bearer 刷新)
path('token/refresh/', CookieTokenRefreshView.as_view(), name='token_refresh'),
# 修复:挂载用户登出端点(清除 HttpOnly Cookie)
path('logout/', UserLogoutAPIView.as_view(), name='user_logout'),
path('regions/', RegionListView.as_view(), name='region_list'),
path('qr-token/', QRTokenView.as_view(), name='qr_token'),
path('qr-status/<str:token>/', QRStatusView.as_view(), name='qr_status'),
path('qr-scan/', QRScanView.as_view(), name='qr_scan'),
path('qr-confirm/', QRConfirmView.as_view(), name='qr_confirm'),
path('qr-cancel/', QRCancelView.as_view(), name='qr_cancel'),
path('follow/<int:user_id>/', FollowToggleView.as_view(), name='follow_toggle'),
path('activities/', UserActivityView.as_view(), name='user_activities'),
path('profile/cover/', UploadCoverAPIView.as_view(), name='upload_cover'),
path('privacy/', PrivacySettingsAPIView.as_view(), name='privacy_settings'),
path('notification-settings/', NotificationSettingsAPIView.as_view(), name='notification_settings'),
path('devices/', UserDeviceListView.as_view(), name='user_devices'),
path('devices/<int:pk>/remove/', UserDeviceRemoveView.as_view(), name='user_device_remove'),
path('devices/clear-others/', UserDeviceClearOthersView.as_view(), name='user_device_clear_others'),
]