为什么在我的 Flask 应用程序中调用 csrf_token() 会引发 "can't concat tuple to bytes" 错误?
Why does calling csrf_token() in my Flask app throw a "can't concat tuple to bytes" error?
我正在尝试将 X-CSRFToken header 包含在 fetch()
调用中,并且根据 Flask-WTF documentation,调用 csrf_token() 来自您的模板将 return 您代码中的令牌。但是,当我进行 csrf_token()
调用时,我的应用会抛出错误。
错误状态:“无法将元组连接到字节。”追溯包含在下面。这是通过 render_template()
呈现的模板中的 Javascript
<script>
const form = document.querySelector("form");
form.addEventListener("submit", function(e){
e.preventDefault();
let opts = {
method: this.method.value,
headers: new Headers({
"X-CSRFToken": "{{ csrf_token() }}"
})
};
if(this.method.value!="GET"){
opts.body = this.data.value;
}
fetch( this.api_endpoint.value, opts );
});
</script>
下面是路由调用的 .py 文件render_template()
from flask import Blueprint, render_template
bp = Blueprint('main', __name__,
template_folder="templates",
static_folder="static")
@bp.route("/")
def index():
return render_template("home.html")
@bp.route("/apitester")
def apitester():
return render_template("apitester.htm")
这是 init.py 文件,其中 app
和 csrf
objects 被实例化
from flask import Flask, render_template
from flask_wtf.csrf import CSRFProtect, CSRFError
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
csrf = CSRFProtect()
def create_app():
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('application.appsettings')
db.init_app(app)
csrf.init_app(app)
@app.errorhandler(404)
def page_not_found(e):
return render_template('404err.htm', reason=e.description), 404
@app.errorhandler(CSRFError)
def handle_csrf_error(e):
return render_template('400err.htm', reason=e.description), 400
with app.app_context():
from exercises.bp import bp as bp_exercise
from main.bp import bp as bp_main
from application.models import Exercise
app.register_blueprint(bp_main, url_prefix="/")
app.register_blueprint(bp_exercise, url_prefix="/exercises")
return app
这是回溯:
Traceback (most recent call last):
File "C:\pyeip\venv\Lib\site-packages\flask_wtf\csrf.py", line 49, in generate_csrf
token = s.dumps(session[field_name])
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\serializer.py", line 167, in dumps
rv = self.make_signer(salt).sign(payload)
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\timed.py", line 42, in sign
return value + sep + self.get_signature(value)
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\signer.py", line 143, in get_signature
key = self.derive_key()
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\signer.py", line 130, in derive_key
return self.digest_method(salt + b"signer" + self.secret_key).digest()
TypeError: can't concat tuple to bytes
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 2464, in __call__
return self.wsgi_app(environ, start_response)
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\pyeip\venv\Lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\pyeip\venv\Lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\pyeip\main\bp.py", line 14, in apitester
return render_template("apitester.htm")
File "C:\pyeip\venv\Lib\site-packages\flask\templating.py", line 137, in render_template
return _render(
File "C:\pyeip\venv\Lib\site-packages\flask\templating.py", line 120, in _render
rv = template.render(context)
File "C:\pyeip\venv\Lib\site-packages\jinja2\environment.py", line 1090, in render
self.environment.handle_exception()
File "C:\pyeip\venv\Lib\site-packages\jinja2\environment.py", line 832, in handle_exception
reraise(*rewrite_traceback_stack(source=source))
File "C:\pyeip\venv\Lib\site-packages\jinja2\_compat.py", line 28, in reraise
raise value.with_traceback(tb)
File "C:\pyeip\main\templates\apitester.htm", line 36, in top-level template code
const token = {{ csrf_token() }};
File "C:\pyeip\venv\Lib\site-packages\flask_wtf\csrf.py", line 52, in generate_csrf
token = s.dumps(session[field_name])
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\serializer.py", line 167, in dumps
rv = self.make_signer(salt).sign(payload)
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\timed.py", line 42, in sign
return value + sep + self.get_signature(value)
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\signer.py", line 143, in get_signature
key = self.derive_key()
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\signer.py", line 130, in derive_key
return self.digest_method(salt + b"signer" + self.secret_key).digest()
TypeError: can't concat tuple to bytes
您的 javascript 需要一个字符串。尝试:
const token = "{{ csrf_token() }}";
为了证明这一点,请在浏览器中查看页面的源代码以查看当前的 const token=
声明。
来自阅读回溯的最后一部分
return self.digest_method(salt + b"signer" + >self.secret_key<).digest()
检查 Flask 应用程序配置中的 SECRET_KEY 值(或 app.secret_key
),查找秘密字符串后的额外逗号。
例如:
SECRET_KEY = "very secret string", # extraneous comma, it's tuple
我正在尝试将 X-CSRFToken header 包含在 fetch()
调用中,并且根据 Flask-WTF documentation,调用 csrf_token() 来自您的模板将 return 您代码中的令牌。但是,当我进行 csrf_token()
调用时,我的应用会抛出错误。
错误状态:“无法将元组连接到字节。”追溯包含在下面。这是通过 render_template()
<script>
const form = document.querySelector("form");
form.addEventListener("submit", function(e){
e.preventDefault();
let opts = {
method: this.method.value,
headers: new Headers({
"X-CSRFToken": "{{ csrf_token() }}"
})
};
if(this.method.value!="GET"){
opts.body = this.data.value;
}
fetch( this.api_endpoint.value, opts );
});
</script>
下面是路由调用的 .py 文件render_template()
from flask import Blueprint, render_template
bp = Blueprint('main', __name__,
template_folder="templates",
static_folder="static")
@bp.route("/")
def index():
return render_template("home.html")
@bp.route("/apitester")
def apitester():
return render_template("apitester.htm")
这是 init.py 文件,其中 app
和 csrf
objects 被实例化
from flask import Flask, render_template
from flask_wtf.csrf import CSRFProtect, CSRFError
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
csrf = CSRFProtect()
def create_app():
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('application.appsettings')
db.init_app(app)
csrf.init_app(app)
@app.errorhandler(404)
def page_not_found(e):
return render_template('404err.htm', reason=e.description), 404
@app.errorhandler(CSRFError)
def handle_csrf_error(e):
return render_template('400err.htm', reason=e.description), 400
with app.app_context():
from exercises.bp import bp as bp_exercise
from main.bp import bp as bp_main
from application.models import Exercise
app.register_blueprint(bp_main, url_prefix="/")
app.register_blueprint(bp_exercise, url_prefix="/exercises")
return app
这是回溯:
Traceback (most recent call last):
File "C:\pyeip\venv\Lib\site-packages\flask_wtf\csrf.py", line 49, in generate_csrf
token = s.dumps(session[field_name])
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\serializer.py", line 167, in dumps
rv = self.make_signer(salt).sign(payload)
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\timed.py", line 42, in sign
return value + sep + self.get_signature(value)
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\signer.py", line 143, in get_signature
key = self.derive_key()
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\signer.py", line 130, in derive_key
return self.digest_method(salt + b"signer" + self.secret_key).digest()
TypeError: can't concat tuple to bytes
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 2464, in __call__
return self.wsgi_app(environ, start_response)
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\pyeip\venv\Lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\pyeip\venv\Lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "C:\pyeip\venv\Lib\site-packages\flask\app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\pyeip\main\bp.py", line 14, in apitester
return render_template("apitester.htm")
File "C:\pyeip\venv\Lib\site-packages\flask\templating.py", line 137, in render_template
return _render(
File "C:\pyeip\venv\Lib\site-packages\flask\templating.py", line 120, in _render
rv = template.render(context)
File "C:\pyeip\venv\Lib\site-packages\jinja2\environment.py", line 1090, in render
self.environment.handle_exception()
File "C:\pyeip\venv\Lib\site-packages\jinja2\environment.py", line 832, in handle_exception
reraise(*rewrite_traceback_stack(source=source))
File "C:\pyeip\venv\Lib\site-packages\jinja2\_compat.py", line 28, in reraise
raise value.with_traceback(tb)
File "C:\pyeip\main\templates\apitester.htm", line 36, in top-level template code
const token = {{ csrf_token() }};
File "C:\pyeip\venv\Lib\site-packages\flask_wtf\csrf.py", line 52, in generate_csrf
token = s.dumps(session[field_name])
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\serializer.py", line 167, in dumps
rv = self.make_signer(salt).sign(payload)
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\timed.py", line 42, in sign
return value + sep + self.get_signature(value)
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\signer.py", line 143, in get_signature
key = self.derive_key()
File "C:\pyeip\venv\Lib\site-packages\itsdangerous\signer.py", line 130, in derive_key
return self.digest_method(salt + b"signer" + self.secret_key).digest()
TypeError: can't concat tuple to bytes
您的 javascript 需要一个字符串。尝试:
const token = "{{ csrf_token() }}";
为了证明这一点,请在浏览器中查看页面的源代码以查看当前的 const token=
声明。
来自阅读回溯的最后一部分
return self.digest_method(salt + b"signer" + >self.secret_key<).digest()
检查 Flask 应用程序配置中的 SECRET_KEY 值(或 app.secret_key
),查找秘密字符串后的额外逗号。
例如:
SECRET_KEY = "very secret string", # extraneous comma, it's tuple