I have a small Django application with a view that I want to restrict to certain users. Anyone from a specific network should be able to see that view without any further au
There's no need to write an authentication backend for the use case you have written. Writing an IP based dispatcher in the middleware layer will likely be sufficient
If your app's url(s) is/are matched, process_request should check for an authenticated django user and match that user to a whitelist.
You can try this decorator. I have tested its working fine:
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
There are two suitable approaches for that kind of authentication:
A sample middleware can be something like:
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
If you are using django authentication and REMOTE_ADDR
is not in ALLOWED_IP_BLOCKS
list, then you can use is_authenticated
to check if related user had logged in or not. But for using is_authenticated
in a custom middleware, your custom middleware must be placed after AuthenticationMiddleware
, because request.user
is set on that level.
MIDDLEWARE_CLASSES = (
...
'django.contrib.auth.middleware.AuthenticationMiddleware',
'path.to.my.NeedToLoginMiddleware',
...
)
request.path
and check if the request url requires ip check/authentication.More info about custom middleware classes
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
You need allow_ip
in you UserProfile model, which save on registration or changes on edit user page
IMO, solving this with Django is fine if it's a small non performance critical site.
It's better to keep the unauthorized users fully at bay using your Apache or Nginx service. For example, in Nginx I have these lines in my site configuration:
include allowed_ips.conf;
deny all;
error_page 403 forbidden.html;
allowed_ips.conf is in /etc/nginx and looks (something) like this:
allow 110.222.333.222; # J Bloggs (sys admin)
allow 777.222.0.0/16; # Government owned
...
I believe this is better because the relatively slow Django processes never get touched by the blocked IPs. This is significant if you are blocking bots or other country address ranges for performance or security reasons.
You can also write a small decorator for this purpose:
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 is in my case a file (allowedIps.py) which stores the regexes for allowed IPs in a tuple like this:
allowedIps = ('^XXX\.XXX\..+\..+$','^XXX\.XXX\.XXX\..+$', '^XXX\.XXX\.XXX\.XXX$')
Hope this can help or give an idea. Note: if you return authenticated_by_ip to the decorated view, your view will have to accept that parameter, you also can just ommit it, if you dont need it. You can also define the regexes more precisely to only accept digits up to three.