models.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. from datetime import datetime, time
  2. from django.core.mail import send_mail
  3. from django.db import models
  4. from django.utils.translation import gettext_lazy as _
  5. from django.utils.http import base36_to_int, int_to_base36
  6. from django.conf import settings
  7. from django.utils.crypto import constant_time_compare, salted_hmac
  8. from .validators import ASCIIUsernameValidator
  9. class User(models.Model):
  10. username = models.CharField(
  11. _('username'),
  12. max_length=25,
  13. unique=True,
  14. help_text=_('Required. 25 characters or fewer. Letters, digits and _ only.'),
  15. validators=[ASCIIUsernameValidator()],
  16. error_messages={
  17. 'unique': _("A _user with that username already exists."),
  18. },
  19. )
  20. password = models.CharField(_('password'), max_length=128)
  21. last_login = models.DateTimeField(_('last login'), blank=True, null=True)
  22. email = models.EmailField(_('email address'), unique=True)
  23. class Meta:
  24. db_table = '_user'
  25. verbose_name = verbose_name_plural = '用户信息表'
  26. def get_root_folder(self):
  27. return self.folders.get(father_folder=None)
  28. def set_password(self, password):
  29. # TODO: 密码强度检验,密码hash存储
  30. self.password = password
  31. def send_email(self, subject, message, from_email=None, **kwargs):
  32. send_mail(subject, message, from_email, [self.email], **kwargs)
  33. def make_token(self):
  34. return self._make_token(_timestamp())
  35. def check_token(self, token):
  36. if not token:
  37. return False
  38. try:
  39. ts_b36, hash_str = token.split('-')
  40. except ValueError:
  41. return False
  42. try:
  43. ts = base36_to_int(ts_b36)
  44. except ValueError:
  45. return False
  46. if self._make_token(ts) != token:
  47. return False
  48. timestamp = _timestamp()
  49. if (timestamp - ts) > settings.PASSWORD_RESET_TIMEOUT:
  50. return False
  51. return True
  52. def _make_token(self, timestamp):
  53. ts_b36 = int_to_base36(timestamp)
  54. salt = settings.SALT
  55. value = self._make_hash_value(timestamp)
  56. secret = settings.SECRET_KEY
  57. hash_str = salted_hmac(
  58. salt, value, secret=secret, algorithm='sha256'
  59. ).hexdigest()[::2]
  60. token = "%s-%s" % (ts_b36, hash_str)
  61. return token
  62. def _make_hash_value(self, timestamp):
  63. return f'{self.pk}{self.password}{timestamp}{self.email}'
  64. def __str__(self):
  65. return self.username
  66. def get_user(request):
  67. if hasattr(request, 'user') and isinstance(request.user, User):
  68. print(f'get user from request.user, username={request.user.username}')
  69. return request.user
  70. username = request.POST.get('username', '')
  71. token = request.POST.get('token', '')
  72. try:
  73. user = User.objects.get(username=username)
  74. if user.check_token(token):
  75. user.tokens.get(token=token)
  76. return user
  77. except:
  78. return None
  79. return None
  80. def _timestamp():
  81. dt = datetime.now()
  82. return int((dt - datetime(2001, 1, 1)).total_seconds())
  83. class LoginToken(models.Model):
  84. user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='tokens')
  85. token = models.CharField(max_length=256)