Django REST Framework外部应用自定义认证失败求助:正确实现方案
正确实现方案
1. 修正登录端点(若采用Token认证)
要是你想让外部应用登录后获取Token,后续用Token调用接口,把登录视图修改为:
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from django.conf import settings from django.contrib.auth.models import User from rest_framework.authtoken.models import Token class ExternalAppLoginView(APIView): def post(self, request): app_username = request.data.get('username') app_password = request.data.get('password') # 验证外部应用传入的账号密码是否匹配配置常量 if app_username == settings.EXTERNAL_APP_USER_NAME and app_password == settings.EXTERNAL_APP_PASSWORD: # 获取系统内预先创建的服务用户 try: user = User.objects.get(username=settings.EXTERNAL_APP_SYSTEM_USERNAME) except User.DoesNotExist: return Response({"detail": "系统服务用户不存在"}, status=status.HTTP_404_NOT_FOUND) # 生成或获取该用户的认证Token token, created = Token.objects.get_or_create(user=user) return Response({"token": token.key}, status=status.HTTP_200_OK) return Response({"detail": "认证失败"}, status=status.HTTP_401_UNAUTHORIZED)
2. 实现自定义认证类
方式一:每次请求携带账号密码直接认证
如果不想让外部应用走登录流程,每次调用接口都传入账号密码验证,使用这个认证类:
from rest_framework import authentication from rest_framework import exceptions from django.conf import settings from django.contrib.auth.models import User class ExternalAppAuthentication(authentication.BaseAuthentication): def authenticate(self, request): # 可从请求体或请求头获取账号密码,建议用请求头更安全 username = request.data.get('username') or request.headers.get('X-External-Username') password = request.data.get('password') or request.headers.get('X-External-Password') if not username or not password: return None # 不处理,交给其他认证类 # 验证账号密码是否匹配配置常量 if username != settings.EXTERNAL_APP_USER_NAME or password != settings.EXTERNAL_APP_PASSWORD: raise exceptions.AuthenticationFailed("外部应用认证失败") # 获取系统内对应的服务用户 try: user = User.objects.get(username=settings.EXTERNAL_APP_SYSTEM_USERNAME) except User.DoesNotExist: raise exceptions.AuthenticationFailed("系统服务用户不存在") return (user, None)
方式二:Token认证(登录后使用Token)
如果采用前面的登录端点获取Token,直接使用DRF自带的TokenAuthentication即可,无需自定义:
from rest_framework.authentication import TokenAuthentication
3. 配置与使用
- 在
settings.py中添加常量配置:
EXTERNAL_APP_USER_NAME = "你的外部应用专属用户名" EXTERNAL_APP_PASSWORD = "你的外部应用专属密码" EXTERNAL_APP_SYSTEM_USERNAME = "external_service" # 需预先在数据库创建该用户
- 在需要开放给外部应用的视图中配置认证:
from rest_framework.permissions import IsAuthenticated from rest_framework.views import APIView class ExternalAccessibleAPIView(APIView): # 选择认证方式:方式一用自定义的ExternalAppAuthentication,方式二用TokenAuthentication authentication_classes = [ExternalAppAuthentication] permission_classes = [IsAuthenticated] def get(self, request): return Response({"data": "外部应用可访问的内容"})
原代码问题分析
- 登录视图变量未定义:
user = models.User.objects.get(username=username)中的username未赋值,需指定系统内的服务用户,而非外部应用传入的用户名。 - 认证类无实际逻辑:继承
SessionAuthentication但未做自定义实现,外部应用通常不依赖Session Cookie,需编写匹配需求的认证逻辑。 - 返回格式不规范:DRF视图建议使用
Response替代HttpResponse,便于外部应用解析返回内容。
内容的提问来源于stack exchange,提问作者StuffHappens
相关产品推荐
相关产品推荐

