如何限制主机上DRF子域名的访问权限?
根据你的需求,这里提供几种不同场景下的实现方式,你可以根据实际情况选择:
1. 完全禁止所有外部访问(包括前端也无法调用)
这种场景适合你不需要任何外部请求访问后端API的情况,最直接的方式是通过反向代理(如Nginx)拦截所有请求,或者通过防火墙限制端口。
Nginx配置拦截
修改你的Nginx配置文件,针对api.domain.com的所有请求直接返回403禁止访问:
server { listen 80; server_name api.domain.com; # 若使用HTTPS,需添加listen 443 ssl;并配置证书 location / { return 403; # 返回禁止访问的状态码 # 也可以重定向到主域名:return 301 https://domain.com; } }
配置完成后重启Nginx,所有访问api.domain.com的请求都会被直接拦截,后端服务不会收到任何请求。
防火墙/安全组限制
如果你的服务器部署在云平台(如阿里云、腾讯云),可以直接在安全组规则中,禁止所有外部IP访问api.domain.com对应的端口(通常是80/443),仅保留服务器内部IP访问(如果有其他内部服务需要调用的话)。
2. 允许前端正常调用,但禁止直接通过浏览器访问API
如果你的Vue前端需要从domain.com调用后端API,但不想让用户直接在浏览器地址栏输入api.domain.com/xxx查看数据,可以通过校验请求来源实现。
Nginx校验请求来源
在Nginx配置中检查请求的Referer或Origin头,仅允许来自domain.com的请求:
server { listen 80; server_name api.domain.com; location / { # 校验Referer(针对GET请求) if ($http_referer !~* ^https?://domain.com/) { return 403; } # 校验Origin(针对POST/PUT等AJAX请求) if ($http_origin !~* ^https?://domain.com$) { return 403; } # 正常转发请求到DRF后端 proxy_pass http://127.0.0.1:8000; # 替换为你的DRF服务地址 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
这种方式下,直接在浏览器输入API地址的请求会因为缺少合法的Referer/Origin头被拦截,而前端的AJAX请求会自动携带这些头,正常访问API。
DRF全局权限控制
在DRF中自定义权限类,校验请求来源:
- 先在项目中创建自定义权限类:
from rest_framework.permissions import BasePermission class AllowOnlyDomainCom(BasePermission): def has_permission(self, request, view): # 校验Origin或Referer origin = request.META.get('HTTP_ORIGIN') referer = request.META.get('HTTP_REFERER') allowed_origin = 'https://domain.com' # 替换为你的主域名 # 允许内部请求(如服务器本地调用)或来自主域名的请求 if origin == allowed_origin or (referer and allowed_origin in referer): return True return False
- 在
settings.py中设置全局默认权限:
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'your_app.permissions.AllowOnlyDomainCom', ] }
这样所有DRF接口都会校验请求来源,不符合条件的返回403。
3. 仅允许管理员访问API
如果需要保留API的访问权限,但仅允许内部管理员使用,可以直接使用DRF自带的权限类:
在settings.py中配置:
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAdminUser', ] }
这样只有后台管理员账号(is_staff=True的用户)能通过认证访问API,其他所有请求都会被拒绝。
内容的提问来源于stack exchange,提问作者Gamigj

