You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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": "外部应用可访问的内容"})

原代码问题分析

  1. 登录视图变量未定义:user = models.User.objects.get(username=username)中的username未赋值,需指定系统内的服务用户,而非外部应用传入的用户名。
  2. 认证类无实际逻辑:继承SessionAuthentication但未做自定义实现,外部应用通常不依赖Session Cookie,需编写匹配需求的认证逻辑。
  3. 返回格式不规范:DRF视图建议使用Response替代HttpResponse,便于外部应用解析返回内容。

内容的提问来源于stack exchange,提问作者StuffHappens

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 04:05:24