1

我已经用 flask-restful 和 flask-jwt-extended 构建了一个 api,并正确配置了令牌过期和失效的验证通道。但是,即使构建了token过期和无效验证回调,api也没有正确处理并报错:Signature has expired

在云中的服务器上,我们有一个 Centos 7 x64 的 16GB 内存,使用版本 19.9.0 的 gunicorn 运行应用程序。使用 miniconda 创建应用程序的 python 环境。

在生产环境的测试中,应用程序抱怨令牌过期。但是在测试环境中,使用 Ubuntu 18.04.2、x64 和 16 gb ram,使用与 miniconda 和 gunicorn 相同的设置,应用程序执行它没有问题,在令牌过期时返回正确的消息。

我的 jwt.py

from flask import Blueprint, Response, json, request
from flask_jwt_extended import (JWTManager, create_access_token,
                                create_refresh_token, get_jwt_identity,
                                jwt_required)

from app.models.core import User

from .schemas import UserSchema
from .utils import send_reponse, user_roles


def configure_jwt(app):
    JWT = JWTManager(app)

    @JWT.expired_token_loader
    def my_expired_token_callback(expired_token):
        return Response(
            response=json.dumps({
                "message": "Expired token"
            }),
            status=401,
            mimetype='application/json'
        )

    @JWT.invalid_token_loader
    def my_invalid_token_callback(invalid_token):
        return Response(
            response=json.dumps({
                "message": "Invalid token"
            }),
            status=422,
            mimetype='application/json'
        )

错误日志:

[2019-05-23 15:42:02 -0300] [3745] [ERROR] Exception on /api/company [POST]
Traceback (most recent call last):
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_restful/__init__.py", line 458, in wrapper
    resp = resource(*args, **kwargs)
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask/views.py", line 88, in view
    return self.dispatch_request(*args, **kwargs)
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_restful/__init__.py", line 573, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_jwt_extended/view_decorators.py", line 102, in wrapper
    verify_jwt_in_request()
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_jwt_extended/view_decorators.py", line 31, in verify_jwt_in_request
    jwt_data = _decode_jwt_from_request(request_type='access')
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_jwt_extended/view_decorators.py", line 266, in _decode_jwt_from_request
    decoded_token = decode_token(encoded_token, csrf_token)
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_jwt_extended/utils.py", line 107, in decode_token
    allow_expired=allow_expired
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/flask_jwt_extended/tokens.py", line 138, in decode_jwt
    leeway=leeway, options=options)
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/jwt/api_jwt.py", line 104, in decode
    self._validate_claims(payload, merged_options, **kwargs)
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/jwt/api_jwt.py", line 134, in _validate_claims
    self._validate_exp(payload, now, leeway)
  File "/home/company/miniconda3/envs/api_ms/lib/python3.6/site-packages/jwt/api_jwt.py", line 175, in _validate_exp
    raise ExpiredSignatureError('Signature has expired')
jwt.exceptions.ExpiredSignatureError: Signature has expired

我试图理解为什么应用程序能够在测试环境中正确返回令牌过期消息,而在生产环境中它返回错误代码500 Internal Server Error。除了在我们的应用程序中解决这个问题。

4

2 回答 2

4

根据在项目存储库中找到的这个链接,我发现问题与名为 的烧瓶配置选项有关PROPAGATE_EXCEPTIONS,它必须是True.

flask-jwt-extended 存储库中的问题帮助我找到了答案。

于 2019-05-23T22:47:25.360 回答
1

此评论指出Flask Restful需要忽略JWTJWT Extended 异常,并提供解决问题的简单代码段。

从上面的链接复制代码,

from flask_jwt_extended.exceptions import JWTExtendedException
from jwt.exceptions import PyJWTError

class FixedApi(Api):
  def error_router(self, original_handler, e):
    if not isinstance(e, PyJWTError) and not isinstance(e, JWTExtendedException) and self._has_fr_route():
      try:
        return self.handle_error(e)
      except Exception:
        pass  # Fall through to original handler
    return original_handler(e)
于 2020-08-03T20:11:51.313 回答