在Django中通过IP地址进行身份验证

时间:2012-09-12 07:53:52

标签: python django authentication

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

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

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

6 个答案:

答案 0 :(得分:11)

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

  • 作为装饰者:如果某些视图(但不是很多)需要进行此项检查,那么最好为其编写一个装饰器(类似于@Jingo已写的)
  • 作为中间件:如果需要通过所有(或多个)视图进行检查,而不是使用装饰器,则编写middleware是更好的解决方案。

示例中间件可以是:

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
  • 您可以使用列表进行ip检查,也可以使用@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',
        ...
    )
    
    • 如果一些视图不需要此身份验证,那么您可以列出例外网址并从request.path获取请求网址并检查请求网址是否需要ip check /认证

有关custom middleware classes

的更多信息

答案 1 :(得分:7)

您还可以为此目的编写一个小装饰器:

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返回到装饰视图,则视图必须接受该参数,如果不需要,也可以省略它。 您还可以更精确地定义正则表达式,以仅接受最多三个数字。

答案 2 :(得分:3)

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

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

答案 3 :(得分:3)

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

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

答案 4 :(得分:2)

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的影响。如果出于性能或安全原因阻止机器人或其他国家/地区范围,这一点很重要。

答案 5 :(得分: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

您在UserProfile模型中需要allow_ip,这样可以节省注册或更改编辑用户页面