Django Rest Framework 避免身份验证 JWT
Posted
技术标签:
【中文标题】Django Rest Framework 避免身份验证 JWT【英文标题】:Django Rest Framework avoid authentication JWT 【发布时间】:2020-04-10 01:01:48 【问题描述】:我正在使用rest_framework_simplejwt
对我的用户进行身份验证,但是在某些视图中我需要忽略它,因为这些是公共视图。我想将令牌检查到视图流中。预期的行为是:
在公众视野中
避免令牌验证:如果有过期或无效的令牌,忽略它,让我在 APIView 中验证它其实rest_framework_simplejwt
会检查token,如果token无效或过期则提升401
...
我尝试在 APIView 中禁用 authentication_classes
,如下所示:
class SpecificProductApi(APIView):
def get_authenticators(self):
if self.request.method == 'GET':
self.authentication_classes = []
return super(SpecificProductApi, self).get_authenticators()
但是如果我在输入 GET APIView
方法之前禁用它,我不能这样做 if reques.user.is_authenticated:
因为我禁用了令牌:(
是否存在一种方法可以进入 api http 方法并手动检查用户进入视图?谢谢
【问题讨论】:
我不明白您这样做时遇到了什么问题request.user.is_authenticated
。你能解释一下问题吗?
您好!感谢您的回答,碰巧如果我使用self.authentication_classes = []
,稍后在使用request.user.is_authenticated
的视图内部无效,它总是返回false,我需要在视图内部手动处理身份验证避免在其外部进行验证,我希望更清楚, 非常感谢:)
我想知道执行此操作的标准方法是什么。像一个规范来处理这个。有人知道吗?
【参考方案1】:
我通过添加 authentication_classes = []
来完成它
from rest_framework import permissions
class SpecificProductApi(APIView):
permission_classes = [permissions.AllowAny]
authentication_classes = []
【讨论】:
简单解决方案【参考方案2】:您可以简单地在视图中使用authentication_classes = []
,但这总是会绕过 JWT 身份验证,即使存在带有令牌的有效 Authorization-header 也是如此。您最好将 JWTAuthentication-class 扩展如下(类似于 Jhon Edwin Sanz Gonzalez 的评论):
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.exceptions import InvalidToken
class JWTAuthenticationSafe(JWTAuthentication):
def authenticate(self, request):
try:
return super().authenticate(request=request)
except InvalidToken:
return None
然后在你的视图中使用authentication_classes = [JWTAuthenticationSafe]
。
【讨论】:
这是最好的答案。【参考方案3】:有一个非常相似的问题。要创建公共端点,您必须覆盖身份验证器,否则您将在过期/丢失的令牌上返回 401/403。
但是,公共端点并不意味着它不应该进行身份验证。相反,它应该对 no-auth / expired-auth 有一个响应,对有效身份验证有另一个响应。
我不知道这是否是“正确”的方式,但这是我遇到同样问题时想到的。
按照您所做的那样覆盖身份验证器,并添加一个额外的方法来验证您视图中的身份验证器。
例如:
class SomeApiView(APIView):
def get_authenticators(self):
# Override standard view authenticators.
# Public endpoint, no auth is enforced.
return []
def get_auth(self):
# Return a generator of all authenticators.
return (auth() for auth in self.authentication_classes)
def get_auth_detail(self, request):
# Evaluate each authenticator and return the first valid authentication.
for auth in self.get_auth():
# You probably need try / except here to catch authenticators
# that are invalid (403/401) in the case of multiple authentication
# classes--such as token auth, session auth, etc...
auth_detail = auth.authenticate(request)
if auth_detail:
return auth_detail
return None, None
def post(self, request):
# Returns a tuple of (User, JWT), can be (None, None)
user, jwt = self.get_auth_detail(request)
# Do your magic based on user value.
if user:
# User is authenticated.
else:
# User is anon / not-authenticated.
【讨论】:
您好,非常感谢,这太棒了。我只是将get_auth_detail
方法更改为try: auth_detail = auth.authenticate(request) except: auth_detail = None
,我不知道为什么但auth_detail = auth.authenticate(request)
引发了Http403 异常,我使用了try catch。我将寻找如何改进该解决方案。非常感谢
如果您定义了多个身份验证类,如会话身份验证、令牌身份验证,那么很可能一个身份验证器将通过,而另一个身份验证器将失败 403。这取决于排序。因此,您可能必须评估所有身份验证器,直到它们都失败或单个有效身份验证。即,尝试/除外。我想我在我的项目中只使用了一个 jwt 身份验证器,所以我没有看到这个问题。【参考方案4】:
您只需要为相关视图指定权限类
from rest_framework.permissions import AllowAny
class SpecificProductApi(APIView):
permission_classes = (AllowAny, )
此权限允许任何人通过 URL 访问此特定视图。
【讨论】:
在我的测试中这不起作用。过期的令牌会触发 401 响应;因此我的回答。以上是关于Django Rest Framework 避免身份验证 JWT的主要内容,如果未能解决你的问题,请参考以下文章
Django Rest Framework 序列化程序中的循环依赖
Django-rest-framework 和 django-rest-framework-jwt APIViews and validation Authorization headers
Django Rest Framework 和 django Rest Framework simplejwt 两因素身份验证