18

我有一个小型 Django 应用程序,我想将其限制为某些用户。来自特定网络的任何人都应该能够看到该视图,而无需任何进一步的身份验证,仅基于 IP 地址。应该要求来自此 IP 范围之外的任何其他人输入密码并根据默认的 Django 用户管理进行身份验证。

我假设我必须为此编写一个自定义身份验证后端,但文档让我感到困惑,因为该authenticate()函数似乎需要用户名/密码组合或令牌。我不清楚如何在这里使用 IP 地址进行身份验证。

在 Django 中实现基于 IP 地址的身份验证的正确方法是什么?我更愿意将尽可能多的现有库函数用于与安全相关的代码,而不是自己编写所有代码。

4

6 回答 6

15

这种身份验证有两种合适的方法:

  • 作为装饰器:如果某些视图(但不是很多)需要这个检查,那么最好为此编写一个装饰器(就像@Jingo 写的那样)
  • 作为中间件:如果需要由所有(或许多)视图完成检查,而不是使用装饰器,编写中间件是更好的解决方案。

示例中间件可能类似于:

ALLOWED_IP_BLOCKS = [......]

class NeedToLoginMiddleware(object):
    def process_request(self, request):
        ip = request.META['REMOTE_ADDR']
        if not ip in ALLOWED_IP_BLOCKS: #ip check
            if not request.user.is_authenticated(): #if ip check failed, make authentication check
                return HttpResponseRedirect(...)
        return None
  • 您可以使用列表或@Jingo 提到的正则表达式进行 ip 检查。
  • 如果您正在使用 django 身份验证并且REMOTE_ADDR不在ALLOWED_IP_BLOCKS列表中,则可以使用is_authenticated检查相关用户是否已登录。但是要is_authenticated在自定义中间件中使用,您的自定义中间件必须放在 之后 AuthenticationMiddleware,因为request.user设置在该级别上。

    MIDDLEWARE_CLASSES = (
        ...
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'path.to.my.NeedToLoginMiddleware',
        ...
    )
    
    • 如果一些视图不需要此身份验证,那么您可以列出异常 url并从中获取请求 urlrequest.path并检查请求 url 是否需要 ip 检查/身份验证。

有关自定义中间件类的更多信息

于 2012-09-12T13:07:44.533 回答
8

为此,您还可以编写一个小型装饰器:

def login_by_ip(view_func):
    def authorize(request, *args, **kwargs):
        user_ip = request.META['REMOTE_ADDR']
        for ip in allowedIps.allowedIps:
            authenticated_by_ip = re.compile(ip).match(user_ip)
            if authenticated_by_ip:
                return view_func(request, authenticated_by_ip, *args, **kwargs)
        return HttpResponseRedirect('/redirect/path/')
    return authorize

在我的例子中,allowedIps 是一个文件(allowedIps.py),它将允许 IP 的正则表达式存储在一个元组中,如下所示:

allowedIps = ('^XXX\.XXX\..+\..+$','^XXX\.XXX\.XXX\..+$', '^XXX\.XXX\.XXX\.XXX$')

希望这可以帮助或给出一个想法。注意:如果您将 authenticated_by_ip 返回到装饰视图,您的视图将必须接受该参数,如果您不需要它也可以省略它。您还可以更精确地定义正则表达式以仅接受最多三位的数字。

于 2012-09-12T08:56:52.880 回答
4

IMO,如果它是一个小型的非性能关键站点,那么用 Django 解决这个问题就可以了。

最好使用您的 Apache 或 Nginx 服务完全阻止未经授权的用户。例如,在 Nginx 中,我的站点配置中有这些行:

include allowed_ips.conf;
deny all;
error_page 403 forbidden.html;

allowed_ips.conf 在 /etc/nginx 中,看起来像这样:

allow 110.222.333.222;  # J Bloggs (sys admin)
allow 777.222.0.0/16;   # Government owned
...

我相信这会更好,因为相对较慢的 Django 进程永远不会被阻止的 IP 触及。如果您出于性能或安全原因而阻止机器人或其他国家/地区地址范围,这很重要。

于 2013-12-30T00:08:18.730 回答
4

你可以试试这个装饰器。我已经测试了它的工作正常:

allowedIps = ['129.0.0.1', '127.0.0.1']
def allow_by_ip(view_func):
    def authorize(request, *args, **kwargs):
        user_ip = request.META['REMOTE_ADDR']
        for ip in allowedIps:
            if ip==user_ip:
                return view_func(request, *args, **kwargs)
        return HttpResponse('Invalid Ip Access!')
    return authorize
于 2015-08-10T14:59:16.467 回答
3

无需为您编写的用例编写身份验证后端。在中间件层编写一个基于 IP 的调度程序可能就足够了

如果您的应用程序的 url 匹配,则 process_request 应检查经过身份验证的 django 用户并将该用户与白名单匹配。

于 2012-09-12T07:58:12.350 回答
1
def login_by_id(request):
    ip = request.META['REMOTE_ADDR']
    try: UserProfile.objects.get(allow_ip=ip)
    except UserProfile.DoesNotExist: return HttpResponseRedirect('././')
    else:
        # auth here

您需要allow_ip在 UserProfile 模型中保存注册或编辑用户页面上的更改

于 2012-09-12T11:40:36.277 回答