TypeError:使用 Flask-JWT 时需要字符串或字节格式的密钥
Posted
技术标签:
【中文标题】TypeError:使用 Flask-JWT 时需要字符串或字节格式的密钥【英文标题】:TypeError: Expecting a string- or bytes-formatted key when using Flask-JWT 【发布时间】:2017-04-06 23:07:49 【问题描述】:我有一个关于烧瓶 python 的问题。 我尝试学习如何使用烧瓶构建网络,但出现了一些错误。在这种情况下,我使用 mongoengine 作为数据库和 JWT(Json Web Token),并且警报错误是这样的:“TypeError: Expecting a string- or bytes-formatted key”
192.168.100.26 - - [22/Nov/2016 22:50:08] "POST /auth HTTP/1.1" 500 -
Traceback (most recent call last):
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 2000, in __call__
return self.wsgi_app(environ, start_response)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1991, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1567, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1988, in wsgi_app
response = self.full_dispatch_request()
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1641, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1544, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
rv = self.dispatch_request()
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1625, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/def/pr/flask/flask_deeper/test/routes/auth.py", line 26, in auth
access_token = _jwt.jwt_encode_callback(identity)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt/__init__.py", line 70, in _default_jwt_encode_handler
return jwt.encode(payload, secret, algorithm=algorithm, headers=headers)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 56, in encode
json_payload, key, algorithm, headers, json_encoder
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jws.py", line 98, in encode
key = alg_obj.prepare_key(key)
File "/usr/local/lib/python2.7/dist-packages/jwt/algorithms.py", line 116, in prepare_key
raise TypeError('Expecting a string- or bytes-formatted key.')
TypeError: Expecting a string- or bytes-formatted key.
我以为是这个问题。
models/user.py
@staticmethod
def jwt_handler(token):
if not User.objects(token=token):
raise JWTError("Bad bad bad bad")
secret = str(current_app.config["JWT_SECRET_KEY"])
algorithm = str(current_app.config["JWT_ALGORITHM"])
options =
'verify_' + claim: True
for claim in verify_claims
options.update(
'require_' + claim: True
for claim in required_claims
)
decode = jwt.decode(token, secret, options=options, algorithms=[algorithm])
return decode
@staticmethod
def authenticate(username, password):
user = User.objects(username=username)
if len(user) == 0:
return None
user = user[0]
user["id"] = str(user["id"])
if crypt.verify(password, user.password):
return user
return user
routes/user.py
def auth():
username = request.form.get("username")
password = request.form.get("password")
if not username:
raise BadRequest("Userna doesn't exists")
user = user_ctrl.read(username)
identity = _jwt.authentication_callback(username, password)
if identity:
access_token = _jwt.jwt_encode_callback(identity)
identity.update(push__token=access.decode("utf8"))
return _jwt.auth_response_callback(access_token, identity)
else:
raise JWTError("Bad bad bad very bad")
config.py
import os
from test.models import db
class Config(object):
db_name = os.getenv('MONGODB_NAME', 'third')
db_host = os.getenv('MONGODB_HOST', '127.0.0.1')
db_port = os.getenv('MONGODB_PORT', '5000')
JWT_SECRET_KEY = 'test123'
JWT_ALGORITHM = 'SH256'
JWT_AUTH_ENDPOINT = 'jwt'
JWT_AUTH_USERNAME_KEY = 'username'
JWT_AUTH_PASSWORD_KEY = 'password'
http.py
import logging.config
import jwt
from flask_jwt import JWT
from flask import Flask
from test import routes
from test.models import db, User
_jwt = JWT(authentication_handler=User.authenticate, identity_handler=User.identity)
_jwt.jwt_decode_callback=User.jwt_handler
def create_app(config):
app = Flask(__name__.split(',')[0])
app.register_blueprint(routes.user.bp)
app.register_blueprint(routes.auth.bp)
db.init_app(app)
_jwt.init_app(app)
return app
【问题讨论】:
回溯说错误在File "/home/def/pr/flask/flask_deeper/test/routes/auth.py", line 26
你能把代码贴在那里吗?
这是第 26 行的代码。access_token = _jwt.jwt_encode_callback(identity)
不,我的意思是整个代码块
@bp.route("/auth", methods=["POST"]) def auth(): username = request.form.get("username") password = request. form.get("password") if not username: raise BadRequest("Userna doesn't exist") user = user_ctrl.read(username) identity = _jwt.authentication_callback(username, password) if identity: access_token = _jwt.jwt_encode_callback( identity) # identity.update(push__token=access.decode("utf8")) return _jwt.auth_response_callback(access_token, identity) else: raise JWTError("Bad bad bad very bad"
您可以“编辑”您的问题并在此处添加代码块(编辑链接在左侧问题的末尾)。粘贴在 cmets 中的代码很难看懂。
【参考方案1】:
您已定义配置为config.py
,但尚未将配置对象添加到您的烧瓶应用程序中。因此,JWT_SECRET_KEY
等键不在您的应用配置中。
Flask-JWT 的 default_handler 需要这些值(复制以防源更改)
def _default_jwt_decode_handler(token):
secret = current_app.config['JWT_SECRET_KEY']
algorithm = current_app.config['JWT_ALGORITHM']
leeway = current_app.config['JWT_LEEWAY']
在您未设置的情况下,它返回None
并触发algorithms.py
(需要一个字符串键)。
因此,在 http.py 中的应用初始化期间,您必须添加对 app.config.from_object
的调用。也许是这样的
def create_app(config):
app = Flask(__name__.split(',')[0])
# Edit the following to point it to your Config class
app.config.from_object(config.Config)
app.register_blueprint(routes.user.bp)
app.register_blueprint(routes.auth.bp)
db.init_app(app)
_jwt.init_app(app)
return app
附带说明,JWT_ALGORITHM
的名称应该是 HS256
而不是 SH256
(尽管这并不重要,因为 HS256
是默认值,并且将被选中,因为 SH256
不是有效的算法)
【讨论】:
以上是关于TypeError:使用 Flask-JWT 时需要字符串或字节格式的密钥的主要内容,如果未能解决你的问题,请参考以下文章
通过 Flask-JWT REST API 使用 Flask-Security 角色
python 报错——Python TypeError: 'module' object is not callable 原因分析