代用户请求需认证API端点时出现「认证凭证未提供」错误
解决「Authentication credentials were not provided.」错误的方案
核心原因
你在视图中调用login(request, user)后,Django默认会在当前请求结束时才将session数据写入数据库。而你立刻用requests发起的新请求,此时这个session还未持久化,导致后端无法识别这个sessionid,认证失败。
另外,用requests发起外部请求调用内部API本身就绕了弯路,不如直接调用业务逻辑更高效可靠。
具体解决方法
方法1:手动保存session后再发起请求
在login之后手动调用request.session.save(),确保session立即写入数据库:
def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) username = serializer.validated_data['username'] password = serializer.validated_data['password'] user = authenticate(request, username=username, password=password) login(request, user) # 新增:手动保存session,确保sessionid已持久化 request.session.save() session_id = request.session.session_key csrf_token = get_token(request) request_headers = { 'X-CSRFToken': csrf_token, 'Cookie': f"sessionid={session_id}", } url_path = reverse('send-mail-confirm-email') full_url = request.scheme + '://' + request.get_host() + url_path requests.get( full_url, headers=request_headers, ) return Response( serializer.data, status=status.HTTP_201_CREATED, headers=headers )
方法2:直接调用内部业务逻辑(推荐)
跳过requests请求,直接调用发送邮件的核心逻辑,彻底避免跨请求的认证问题:
- 先把发送确认邮件的逻辑抽成独立函数(比如放在
utils.py中):
# utils.py from django.core.mail import send_mail from django.conf import settings def send_confirm_email(user): # 这里写发送确认邮件的具体逻辑 subject = "请确认你的邮箱" confirm_url = f"{settings.SITE_PROTOCOL}://{settings.SITE_DOMAIN}/email-confirm/{user.pk}/" message = f"点击下方链接完成邮箱确认:\n{confirm_url}" send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email])
- 在视图中直接调用这个函数:
def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.save() # perform_create内部就是调用save,直接拿到创建好的user对象 headers = self.get_success_headers(serializer.data) username = serializer.validated_data['username'] password = serializer.validated_data['password'] user = authenticate(request, username=username, password=password) login(request, user) # 直接调用发送邮件逻辑,无需跨请求认证 send_confirm_email(user) return Response( serializer.data, status=status.HTTP_201_CREATED, headers=headers )
方法3:检查API的认证配置
确认send-mail-confirm-email对应的视图使用的是SessionAuthentication:
from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated class SendMailConfirmEmailView(APIView): authentication_classes = [SessionAuthentication] permission_classes = [IsAuthenticated] def get(self, request): # 视图业务逻辑 ...
如果该API用的是TokenAuthentication,那你需要生成并传递Token,而非sessionid。
内容的提问来源于stack exchange,提问作者SolnLase
相关产品推荐
相关产品推荐

