Flask中请求体的请求开启CSRF保护可以按以下配置
from flask_wtf.csrf import CSRFProtect
app.config.from_object(Config)
CSRFProtect(app)
#像任何其它的 Flask 扩展一样,你可以惰性加载它:
from flask_wtf.csrf import CsrfProtect
csrf = CsrfProtect()
def create_app():
app = Flask(__name__)
csrf.init_app(app)
但CSRFProtect只做验证工作,cookie中的 csrf_token 和表单中的 csrf_token 需要按以下方式实现
根据 csrf_token 校验原理,具体操作步骤有以下几步:
1、后端生成 csrf_token 的值,在前端请求登录或者注册界面的时候将值传给前端,传给前端的方式可能有以下两种:
(1)在模板中的 From 表单中添加隐藏字段
(2)将 csrf_token 使用 cookie 的方式传给前端
2、在前端发起请求时,在表单或者在请求头中带上指定的 csrf_token
3、后端在接受到请求之后,取到前端发送过来的 csrf_token,与第1步生成的 csrf_token 的值进行校验
4、如果校验对 csrf_token 一致,则代表是正常的请求,否则可能是伪造请求,不予通过
生成 csrf_token 的值
# 导入生成 csrf_token 值的函数
from flask_wtf.csrf import generate_csrf
# 调用函数生成 csrf_token
csrf_token = generate_csrf()
将 csrf_token 的值传给前端浏览器 实现思路:可以在请求勾子函数中完成此逻辑
通过装饰器为一个模块添加请求钩子, 对当前模块的请求进行额外的处理. 比如权限验证,请求钩子放在app文件加的 __init__.py create_app函数中
def create_app(config_name):
app = Flask(__name__)
#请求钩子
@app.after_request
def after_request(response):
# 调用函数生成 csrf_token
csrf_token = generate_csrf()
# 通过 cookie 将值传给前端
response.set_cookie("csrf_token", csrf_token)
return response
在前端请求时带上 csrf_token 值
(1)根据登录和注册的业务逻辑,当前采用的是 ajax 请求
(2)所以在提交登录或者注册请求时,需要在请求头中添加 X-CSRFToken
的键值对
$.ajax({
url:"/passport/register",
type: "post",
headers: {
"X-CSRFToken": getCookie("csrf_token")
},
// 自定义 getCookie 函数来拿到cookie中的 csrf_token 值(可不写)
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;}
data: JSON.stringify(params),
contentType: "application/json",
success: function (resp) {
if (resp.errno == "0"){
// 刷新当前界面
location.reload()
}else {
$("#register-password-err").html(resp.errmsg)
$("#register-password-err").show()
}
}
})
如果模板中有表单,不需要做任何事
<form method="post">
{{ form.csrf_token }}
或者:
{{form.hidden_tag()}}
...
</form>
但如果模板中没有表单,你仍需要 CSRF 令牌:
<form method="post" action="/">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
</form>
如果使用 csrf_token()
函数来作为 token 的值, 你需要设置 X-CSRFToken
请求头
路由想取消 csrf_token认证
在不需要csrf_token
认证的路由中
加一个装饰器 @csrf.exempt 就可以取消csrf_token认证