如何在Django REST Framework中配置多认证类实现API双访问方式?
解决DRF中同时支持两种认证方式的问题
你遇到的问题是因为DRF的authentication_classes需要接收一个认证类的列表/元组,而不是用|符号进行位运算操作——这个符号在Python里是按位或,完全不适合用来组合认证类。下面是具体的解决方法:
1. 正确配置视图集的认证类列表
直接把你的两个认证类放进列表里,DRF会按顺序尝试每个认证类,只要其中一个认证成功,就会使用该认证结果;如果所有认证都失败,才会返回401未认证。
示例代码:
from rest_framework.viewsets import ModelViewSet from rest_framework.authentication import OAuth2Authentication from .path_to_your_auth import ClientAuthentication # 导入你的自定义认证类 class YourTargetViewSet(ModelViewSet): # 按你期望的优先级排序,这里先试Client认证,再试OAuth2 authentication_classes = [ClientAuthentication, OAuth2Authentication] # 其他视图集配置 # serializer_class = YourSerializer # queryset = YourModel.objects.all()
2. 调整自定义认证类的逻辑(关键)
你当前的ClientAuthentication在认证失败时直接抛出AuthenticationFailed异常,这会导致DRF立即终止认证流程,不会尝试后续的OAuth2Authentication。如果希望两种认证方式都能被尝试,需要修改authenticate方法,在认证不通过时返回None,而不是抛出异常。
修改后的自定义认证类:
from rest_framework import authentication, exceptions from .models import Application class ClientAuthentication(authentication.BaseAuthentication): @staticmethod def get_client_credentials(request): # 不需要try-except,headers.get()不会抛出异常,只会返回None client_id = request.headers.get('CLIENTID') client_secret = request.headers.get('CLIENTSECRET') return { 'client_id': client_id, 'client_secret': client_secret } def authenticate(self, request): credentials = self.get_client_credentials(request) # 如果没有提供client_id或client_secret,直接返回None,让DRF尝试下一个认证 if not credentials['client_id'] or not credentials['client_secret']: return None client_instance = Application.objects.filter( client_id=credentials['client_id'], client_secret=credentials['client_secret'], ).first() # 凭证无效时返回None,继续尝试后续认证 if not client_instance: return None # 认证成功,返回(认证主体, None),这里用client_instance作为认证后的主体 return (client_instance, None) # 注意:get_user_application不是DRF认证类的标准方法,如果没有特殊需求可以删除 # 保留的话也不会影响认证流程,但建议只保留DRF规范的方法
3. 验证逻辑
现在当请求进来时:
- 如果请求头带有有效的
CLIENTID和CLIENTSECRET,ClientAuthentication会认证成功,请求正常处理; - 如果Client认证失败(比如凭证无效或未提供),DRF会自动尝试
OAuth2Authentication,如果请求带有有效的access token,就能通过认证; - 如果两种认证都失败,才会返回401 Unauthorized。
内容的提问来源于stack exchange,提问作者Aarti Joshi
相关产品推荐
相关产品推荐

