如何在Django中配置用户仅拥有REST API访问权限?
核心逻辑
给目标用户加个「仅API访问」的标识,然后分别在网页登录/访问流程里拦截这类用户,同时允许他们正常通过API获取Token。不需要完全自定义权限类,用现有框架组件组合就能搞定。
具体操作步骤
1. 给用户模型加标识字段
不管用默认用户模型还是自定义的,新增一个布尔字段来标记这类用户:
# models.py from django.contrib.auth.models import AbstractUser class CustomUser(AbstractUser): is_api_only = models.BooleanField(default=False, help_text="勾选后该用户仅能通过API访问")
之后在settings.py里指定自定义用户模型:AUTH_USER_MODEL = '你的应用名.CustomUser',然后跑数据库迁移命令python manage.py makemigrations和migrate。
2. 拦截网页端的登录请求
重写Django自带的登录视图,校验用户是否是API-only用户,是就拒绝登录:
# views.py from django.contrib.auth.views import LoginView from django.contrib import messages class RestrictedLoginView(LoginView): def form_valid(self, form): user = form.get_user() if user.is_api_only: messages.error(self.request, "这个账号只能用API访问,不能登录网页") return self.form_invalid(form) return super().form_valid(form)
然后把urls里的登录路由指向这个自定义视图,替换原来的django.contrib.auth.views.LoginView。
3. 拦截已登录API用户的网页访问
加个全局中间件,检查已登录用户如果是API-only类型,且访问的是非API路径,就强制退出并返回禁止访问:
# middleware.py from django.shortcuts import HttpResponseForbidden from django.contrib.auth import logout class BlockAPIOnlyUsersMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): if request.user.is_authenticated and request.user.is_api_only: # 排除API路径,这里假设你的API都以/api/开头,可根据实际调整 if not request.path.startswith('/api/'): logout(request) return HttpResponseForbidden("该账号仅支持API访问") response = self.get_response(request) return response
在settings.py的MIDDLEWARE列表里添加这个中间件,注意要放在django.contrib.auth.middleware.AuthenticationMiddleware之后,这样才能拿到已认证的用户。
4. 确保API Token认证正常放行
如果用DRF的TokenAuthentication,默认只要用户有效就能获取Token,不需要额外修改。如果是自定义的Token获取接口,只要不排斥is_api_only用户就行,比如:
# views.py(DRF Token获取示例) from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.response import Response from rest_framework.authtoken.models import Token class APIOnlyObtainAuthToken(ObtainAuthToken): def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] token, _ = Token.objects.get_or_create(user=user) return Response({'token': token.key})
把这个视图挂载到API的Token路由上即可。
关于开箱即用的问题
没有直接开箱即用的配置项,因为默认的权限系统不会区分用户的访问渠道,但通过上面的方法——给用户加标识+自定义视图/中间件——就能实现,不需要从零编写复杂的权限类,都是基于现有框架功能扩展的。
内容的提问来源于stack exchange,提问作者sers

