15👍
There are two suitable approaches for that kind of authentication:
- As Decorator: if some of views (but not many of them) requires this check, then it is better to write a decorator for that (something like @Jingo had written)
- As Middleware: if that check needed to be done by all (or many) views, instead of using a decorator, writing a middleware is a better solution.
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
- You can make ip check using a list, or a regex as @Jingo mentioned.
-
If you are using django authentication and
REMOTE_ADDR
is not inALLOWED_IP_BLOCKS
list, then you can useis_authenticated
to check if related user had logged in or not. But for usingis_authenticated
in a custom middleware, your custom middleware must be placed afterAuthenticationMiddleware
, becauserequest.user
is set on that level.MIDDLEWARE_CLASSES = ( ... 'django.contrib.auth.middleware.AuthenticationMiddleware', 'path.to.my.NeedToLoginMiddleware', ... )
- If a few views do not require this authentication, then you can make a list of exceptional urls and get the request url from
request.path
and check if the request url requires ip check/authentication.
- If a few views do not require this authentication, then you can make a list of exceptional urls and get the request url from
More info about custom middleware classes
8👍
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.
- [Django]-Speeding up Django Testing
- [Django]-Suppress "?next=blah" behavior in django's login_required decorator
- [Django]-Uninstall Django completely
5👍
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.
- [Django]-How to change empty_label for modelForm choice field?
- [Django]-Django 2, python 3.4 cannot decode urlsafe_base64_decode(uidb64)
- [Django]-Django {% if forloop.first %} question
4👍
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
- [Django]-How to specify an IP address with Django test client?
- [Django]-How do I use an UpdateView to update a Django Model?
- [Django]-The QuerySet value for an exact lookup must be limited to one result using slicing. Filter error
3👍
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.
- [Django]-How to delete project in django
- [Django]-How does one make logging color in Django/Google App Engine?
- [Django]-What are the limitations of Django's ORM?
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
You need allow_ip
in you UserProfile model, which save on registration or changes on edit user page
- [Django]-Handling race condition in model.save()
- [Django]-How to go from django image field to PIL image and back?
- [Django]-Running Django with FastCGI or with mod_python