首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与django和JWT在N分钟后的Relogin

与django和JWT在N分钟后的Relogin
EN

Stack Overflow用户
提问于 2018-10-26 10:33:25
回答 3查看 1K关注 0票数 7

场景:我希望用户在N分钟后传递到安全敏感区域时重新登录,例如当用户将要支付订单时,不管他在1小时前登录,我想确定是他。这是通过使用rest_framework_jwt

Long描述:

我最近一直在测试django的现代web开发(所以,后端与rest)。然而,我遇到了一个问题,我还没有找到解决办法。

rest_framework_jwt中,您将身份验证类设置如下。

代码语言:javascript
复制
'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已经为这个场景做了些什么,我想避免重新发明轮子。

EN

回答 3

Stack Overflow用户

发布于 2018-10-29 21:30:21

好吧..。到目前为止,我所做的就是为函数视图创建一个装饰器。装饰师的代码如下:

代码语言:javascript
复制
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 (叉)中的一个即席参数。

最后,为了使用它,可以将装饰器添加到任何视图中。例如:

代码语言:javascript
复制
@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执行。

票数 0
EN

Stack Overflow用户

发布于 2018-10-31 16:31:52

根据手册:https://getblimp.github.io/django-rest-framework-jwt/#additional-settings

不允许刷新令牌应该完成此工作。问题是,您将只得到一个令牌,您将无法在1小时后刷新它。

代码语言:javascript
复制
JWT_AUTH = {
    'JWT_ALLOW_REFRESH': False,
    'JWT_REFRESH_EXPIRATION_DELTA': timedelta(hours=1),
}

其他的问题应该从正面解决。您应该检查用户是否试图进入“敏感”视图。如果是,则检查令牌是否有效。如果无效-重定向到登录页面。如果视图是“不敏感的”-你的选择。

票数 0
EN

Stack Overflow用户

发布于 2018-11-06 13:32:29

处理此问题的推荐方法是将令牌新鲜度与令牌验证分离开来。大多数视图都需要一个有效的令牌,安全视图需要一个新的令牌,这个令牌不仅有效,而且在登录时已经发出,此后就没有被刷新过。

您可以在令牌上设置一个标志,在登录时将其标记为“新鲜”,但在刷新时取消该标志。然后,流动变成:

  1. 客户端访问站点时不使用令牌->拒绝访问。
  2. 客户端使用获取令牌端点->进行身份验证,使用fresh=True发出令牌。
  3. 客户端(或服务器)用fresh=False刷新有效令牌fresh=False问题令牌
  4. 客户端使用有效的令牌访问非安全端点,->接受令牌。
  5. 只有在令牌上设置了->时,客户端才访问安全端点fresh=True接受令牌。

获得新令牌的唯一方法是再次登录,不允许刷新。

所以你需要能够:

  • 在生成JWT有效负载时,区分获取新令牌和刷新。
  • 检查当前JWT令牌中的fresh键,以便创建一个自定义许可

第一个要求意味着您必须执行一些视图子类化,因为jwt_payload_handler回调没有被提供任何信息来确定它的名称。

处理第一个需求的最简单方法是只对序列化器,用于生成新的或刷新的令牌。子类,解码它们产生的令牌,注入适用的fresh键值,然后重新编码。然后使用子类序列化程序创建新的一组API视图

代码语言:javascript
复制
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类在将属性身份验证设置为有效载荷字典时返回解码的有效载荷,因此允许我们在自定义权限中直接检查它:

代码语言:javascript
复制
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框架:

代码语言:javascript
复制
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
        'yourmodule.HashFreshTokenPermission',
    ),
    # ...
}

并在安全性敏感的视图中使用此方法:

代码语言:javascript
复制
class SampleSecureView(APIView):
    permission_classes = (
        permissions.IsAuthenticated,
        HashFreshTokenPermission,
    )
    # ...
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53006797

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档