wrapper.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. from functools import wraps
  6. from django.conf import settings
  7. from typing import Any, TYPE_CHECKING
  8. from apps import serviceCache
  9. from apps.web.core.utils import JsonErrorResponse
  10. from apps.web.utils import get_client_ip
  11. if TYPE_CHECKING:
  12. from apps.web.core.db import RoleBaseDocument
  13. from django.core.handlers.wsgi import WSGIRequest
  14. from django.http import HttpResponse
  15. def request_limit_by_user(operation='common', limit=50, period=24 * 60 * 60, logger=None):
  16. """
  17. http请求速率限制(按照用户ID)
  18. :param logger:
  19. :param operation: 操作
  20. :param limit: 限制次数
  21. :param period: 时长
  22. :return:
  23. """
  24. logger = logging.getLogger(__name__) if logger is None else logger
  25. def decorate(func):
  26. @wraps(func)
  27. def wrapper(request, *args, **kwargs):
  28. # type:(WSGIRequest, *Any, **Any)->HttpResponse
  29. if not settings.ENABLE_REQUEST_LIMIT:
  30. logger.debug('request limit is disable.')
  31. return func(request, *args, **kwargs)
  32. user = request.user # type: RoleBaseDocument
  33. dayTime = datetime.datetime.now().strftime('%Y-%m-%d')
  34. key = '{}_{}_{}'.format(user.request_limit_key, operation, dayTime)
  35. value = serviceCache.get(key, 0)
  36. if value >= limit:
  37. logger.debug("{} in {} exceed max limit.".format(key, get_client_ip(request)))
  38. return JsonErrorResponse(description=u'操作过于频繁,休息一下喔。')
  39. else:
  40. value += 1
  41. serviceCache.set(key, value, period)
  42. return func(request, *args, **kwargs)
  43. return wrapper
  44. return decorate
  45. def request_limit_by_ip(operation='common', limit=50, period=24 * 60 * 60, logger=None):
  46. """
  47. http请求速率限制(按照IP)
  48. :param logger:
  49. :param operation: 操作
  50. :param limit: 限制次数
  51. :param period: 时长
  52. :return:
  53. """
  54. logger = logging.getLogger(__name__) if logger is None else logger
  55. def decorate(func):
  56. @wraps(func)
  57. def wrapper(request, *args, **kwargs):
  58. # type:(WSGIRequest, *Any, **Any)->HttpResponse
  59. if not settings.ENABLE_REQUEST_LIMIT:
  60. logger.debug('request limit is disable.')
  61. return func(request, *args, **kwargs)
  62. ip = get_client_ip(request)
  63. dayTime = datetime.datetime.now().strftime('%Y-%m-%d')
  64. key = '{}_{}_{}'.format(ip, operation, dayTime)
  65. value = serviceCache.get(key, 0)
  66. if value >= limit:
  67. logger.debug("{} in {} exceed max limit.".format(operation, ip))
  68. return JsonErrorResponse(description=u'操作过于频繁,休息一下喔。')
  69. else:
  70. value += 1
  71. serviceCache.set(key, value, period)
  72. return func(request, *args, **kwargs)
  73. return wrapper
  74. return decorate