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.