【问题标题】:Set a IP Whitelist For Each User in Django在 Django 中为每个用户设置一个 IP 白名单
【发布时间】:2020-04-18 10:22:21
【问题描述】:

我希望当用户打算登录时,如果用户从新 IP 地址登录,他们的登录失败

以及包含此内容的电子邮件:

您从一个新的 IP 地址 (109.169.65.137) 登录您要添加 这个 IP 给你允许的 IP-LIST"

将发送到他们的电子邮件。

提示:如果用户允许的 IP_LIST 为 None,用户可以从任何 IP 地址登录

谁能指导我实现这个场景?

我正在使用自定义用户模型

class CustomUserManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, email, mobile_number, password, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        if not email:
            raise ValueError('The given email must be set')
        email   = self.normalize_email(email)
        mobile_number   = mobile_number
        user    = self.model(email=email, mobile_number= mobile_number, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email, mobile_number, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(email, mobile_number, password, **extra_fields)

    def create_superuser(self, email, mobile_number, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_active') is not True:
            raise ValueError('Superuser must have is_active=True.')
        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(email, mobile_number, password, **extra_fields)


class User(AbstractUser):
    username        = None
    email           = models.EmailField(_('email address'), unique=True, validators= [validate_email])
    mobile_number   = models.CharField(_("mobile number"), max_length=11, unique = True, validators= [validate_mobile_number])

    USERNAME_FIELD  = 'email'
    REQUIRED_FIELDS = ['mobile_number']

    objects = CustomUserManager()

    def __str__(self):
        return self.email

    def get_full_name(self):
        return "{} {}".format(self.first_name, self.last_name)

【问题讨论】:

  • 首先你需要为每个用户存储这个IP白名单,如果你使用postgres你可以使用一个数组字段
  • @iain-shelvington 然后呢!?

标签: python django django-models django-rest-framework django-authentication


【解决方案1】:

首先您需要一个字段来存储用户允许的 IP

from django.contrib.postgres.fields import ArrayField

class User(AbstractUser):
    allowed_ips = ArrayField(models.CharField(max_length=20), default=list)

然后您需要一个自定义身份验证后端来处理拒绝或允许用户根据其 IP 进行身份验证。我们可以为此子类化ModelBackend

from django.contrib.auth.backends import ModelBackend

class IPBasedModelBackend(ModelBackend):

    def authenticate(self, request, username=None, password=None, **kwargs):
        user = super().authenticate(request, username=None, password=None, **kwargs)
        if user: # The user passed password validation
            ip = request.META['REMOTE_ADDR']
            if not user.allowed_ips:
                user.allowed_ips.append(ip)
                user.save()
                return user
            elif ip not in user.allowed_ips:
                send_email()
                return
            else:
                return user

那你需要更改AUTHENTICATION_BACKENDS设置

AUTHENTICATION_BACKENDS = ['app.backends.IPBasedModelBackend']

电子邮件需要提供返回应用中视图的链接,该链接将 IP 附加到 user.allowed_ips

def add_allowed_ip(request):
    ip = request.GET.get('ip')  # Not sure this would be the most secure place to put it...
    user_id = request.GET.get('user_id')  # Same here...
    user = User.objects.get(id=user_id)
    user.allowed_ips.append(ip)
    user.save()
    return redirect('login')

【讨论】:

  • 当用户使用新的 ip 地址时,用户无法登录,所以在该用户点击我们的链接并发送到我的视图和 add_allowed_ip 函数调用用户不进行身份验证之后,我们如何获得 user_id ? user_id = request.GET.get('user_id')
  • 如果您要使用上面给出的视图,您可以将user_id 添加到您在模板中发送的 URL 的查询字符串中
猜你喜欢
  • 1970-01-01
  • 2019-03-22
  • 2015-06-06
  • 2017-11-30
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
  • 2012-02-02
  • 1970-01-01
相关资源
最近更新 更多