场景:我希望用户在N分钟后传递到安全敏感区域时重新登录,例如当用户将要支付订单时,不管他在1小时前登录,我想确定是他。这是通过使用rest_framework_jwt。
Long描述:
我最近一直在测试django的现代web开发(所以,后端与rest)。然而,我遇到了一个问题,我还没有找到解决办法。
在rest_framework_jwt中,您将身份验证类设置如下。
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',这将为一般目的做一项伟大的工作。然而,我希望用户重新识别(重新登录)时,进入一个区域与合理的信息10分钟后登录,例如,合理的信息可以是一个支付区域。因此,我想向身份验证类发送一个参数,告诉用户在一个合理的区域。
我认为可能的解决方案(但我还不知道如何实现)是:rest_framework_jwt在使用选项JWT_ALLOW_REFRESH时创建变量orig_iat。我可以向身份验证类发送一个标志,以判断当前视图是否是一个敏感区域,如果是这样,并且用户10分钟前登录,我可以发送一条消息,说明用户需要重新登录才能继续。
我不介意分叉rest_framework_jwt项目并为我的目的对其进行调整,但是我想知道如何将参数从视图发送到身份验证类(在本例中为:rest_framework_jwt.authentication.JSONWebTokenAuthentication)。
另外,如果rest_framework_jwt已经为这个场景做了些什么,我想避免重新发明轮子。
发布于 2018-10-29 21:30:21
好吧..。到目前为止,我所做的就是为函数视图创建一个装饰器。装饰师的代码如下:
from functools import wraps
from rest_framework_jwt.settings import api_settings
from django.utils.translation import ugettext as _
from calendar import timegm
import datetime
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
def recently_authenticated():
def decorator(func):
@wraps(func)
def inner(request, *args, **kwargs):
jwt_payload = jwt_decode_handler(request._auth)
rencent_auth_limit = api_settings.JWT_RECENT_AUTHENTICATION_DELTA
if isinstance(rencent_auth_limit, datetime.timedelta):
rencent_auth_limit = (rencent_auth_limit.days * 24 * 3600 +
rencent_auth_limit.seconds) + jwt_payload["orig_iat"]
timenow = timegm(datetime.datetime.utcnow().utctimetuple())
if timenow>rencent_auth_limit:
return Response({"detail":_("you have to reidentify to enter this area")},
status=401)
return func(request, *args, **kwargs)
return inner
return decorator响应格式以与rest_framework_jwt.authentication.JSONWebTokenAuthentication相同的格式提供。常量JWT_RECENT_AUTHENTICATION_DELTA是插入到rest_framework_jwt包的settings.py (叉)中的一个即席参数。
最后,为了使用它,可以将装饰器添加到任何视图中。例如:
@api_view()
@recently_authenticated()
def index_view(request):
data = User.objects.filter()
return Response(UserSerializer(data, many=True).data)当用户在一段时间前已经通过身份验证时,它将使用代码{"detail":"you have to reidentify to enter this area"}发送消息401。这可以由前端进行评估和分析,并将用户重定向到登录。
注意:装饰器只计算时间和传递的时间。验证是否是正确的用户和正确的令牌仍然由rest_framework_jwt.authentication.JSONWebTokenAuthentication执行。
发布于 2018-10-31 16:31:52
根据手册:https://getblimp.github.io/django-rest-framework-jwt/#additional-settings
不允许刷新令牌应该完成此工作。问题是,您将只得到一个令牌,您将无法在1小时后刷新它。
JWT_AUTH = {
'JWT_ALLOW_REFRESH': False,
'JWT_REFRESH_EXPIRATION_DELTA': timedelta(hours=1),
}其他的问题应该从正面解决。您应该检查用户是否试图进入“敏感”视图。如果是,则检查令牌是否有效。如果无效-重定向到登录页面。如果视图是“不敏感的”-你的选择。
发布于 2018-11-06 13:32:29
处理此问题的推荐方法是将令牌新鲜度与令牌验证分离开来。大多数视图都需要一个有效的令牌,安全视图需要一个新的令牌,这个令牌不仅有效,而且在登录时已经发出,此后就没有被刷新过。
您可以在令牌上设置一个标志,在登录时将其标记为“新鲜”,但在刷新时取消该标志。然后,流动变成:
fresh=True发出令牌。fresh=False刷新有效令牌fresh=False问题令牌fresh=True接受令牌。获得新令牌的唯一方法是再次登录,不允许刷新。
所以你需要能够:
fresh键,以便创建一个自定义许可。第一个要求意味着您必须执行一些视图子类化,因为jwt_payload_handler回调没有被提供任何信息来确定它的名称。
处理第一个需求的最简单方法是只对序列化器,用于生成新的或刷新的令牌。子类,解码它们产生的令牌,注入适用的fresh键值,然后重新编码。然后使用子类序列化程序创建新的一组API视图。
from rest_framework_jwt.settings import api_settings
from rest_framework_jwt.serializers import JSONWebTokenSerializer, RefreshJSONWebTokenSerializer
from rest_framework_jwt.views import JSONWebTokenAPIView
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
class FreshJSONWebTokenSerializer(JSONWebTokenSerializer):
"""Add a 'fresh=True' flag to the JWT token when issuing"""
def validate(self, *args, **kwargs):
result = super().validate(*args, **kwargs)
payload = jwt_decode_handler(result['token'])
return {
**result,
'token': jwt_encode_handler({**payload, fresh=True})
}
class NonFreshRefreshJSONWebTokenSerializer(RefreshJSONWebTokenSerializer):
"""Set the 'fresh' flag False on refresh"""
def validate(self, *args, **kwargs):
result = super().validate(*args, **kwargs)
payload = jwt_decode_handler(result['token'])
return {
**result,
'token': jwt_encode_handler({**payload, fresh=False})
}
class ObtainFreshJSONWebToken(JSONWebTokenAPIView):
serializer_class = JSONWebTokenSerializer
class NonFreshRefreshJSONWebToken(JSONWebTokenAPIView):
serializer_class = NonFreshRefreshJSONWebTokenSerializer
obtain_jwt_token = ObtainFreshJSONWebToken.as_view()
refresh_jwt_token = NonFreshRefreshJSONWebToken.as_view()然后将这两个视图注册为API端点,而不是Django REST Framework项目提供的端点,以便获取和刷新路径。
接下来是权限;因为JSONWebTokenAuthentication类在将属性身份验证设置为有效载荷字典时返回解码的有效载荷,因此允许我们在自定义权限中直接检查它:
class HashFreshTokenPermission(permissions.BasePermission):
message = 'This endpoint requires a fresh token, please obtain a new token.'
def has_permission(self, request, view):
return (
request.user and
request.user.is_authenticated and
request.auth and
isinstance(request.auth, dict) and
request.auth.get('fresh', False)
)将此权限注册到REST框架:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
'yourmodule.HashFreshTokenPermission',
),
# ...
}并在安全性敏感的视图中使用此方法:
class SampleSecureView(APIView):
permission_classes = (
permissions.IsAuthenticated,
HashFreshTokenPermission,
)
# ...https://stackoverflow.com/questions/53006797
复制相似问题