Here is how to setup a list of IP addresses / subnets that are allowed to call a Django Rest Framework endpoint. All other IP addresses will be blocked. Using an IP safe list is much easier than dealing with username or token authentication for a REST endpoint. This works great in cases where the API is only used internally by a handful of clients.
First add a list of IP addresses, or IP patterns, to the settings.py file:
REST_SAFE_LIST_IPS = [ '127.0.0.1', '123.45.67.89', # example IP '192.168.0.', # the local subnet, stop typing when subnet is filled out ]
Next setup a class that extends DRF’s BasePermission class:
class SafelistPermission(permissions.BasePermission): """ Ensure the request's IP address is on the safe list configured in Django settings. """ def has_permission(self, request, view): remote_addr = request.META['REMOTE_ADDR'] for valid_ip in settings.REST_SAFE_LIST_IPS: if remote_addr == valid_ip or remote_addr.startswith(valid_ip): return True return False
This code will do an exact match or a ‘starts with’ match.
The ‘starts with’ match is a quick way to allow a /24 subnet (255.255.255.0). This logic doesn’t support CIDR notation. If the requester’s IP is 192.168.0.101
, and 192.168.0.
is in REST_SAFE_LIST_IPS
above, the function will return True
.
Wiring this all together:
Django Rest Framework has a setting called DEFAULT_PERMISSION_CLASSES
which can be configured to use the little function above, if you want ALL endpoints to default to this permission logic.
REST_FRAMEWORK = { ... 'DEFAULT_PERMISSION_CLASSES': ( 'yourapp.SafelistPermission', # see REST_SAFE_LIST_IPS ) }
Or you can apply it view by view using the permission_classes
property. See the Django Rest Framework -> API Guide -> Permissions section for details.
* A point of political correctness here – blacklist / whitelist could be seen as culturally insensitive, similar to the master/slave vs primary/replica issue in database and storage technology. Blocked list / safe list is much better, although other terms like allow / deny work well too, more ideas here. That is how I coded it in the examples above and I hope you will too.