《Flask Web开发》笔记——第四章 Web表单

在Flask中,需要用到Flask-WTF来处理表单。 这个扩展对独立的 WTForms包进行了包装,方便集成到 Flask 程序中。

4.1 跨站请求伪造保护

首先来看看,什么是跨站请求伪造,以下引用百度百科的描述:
跨站请求伪造(Cross-site request forgery),也被称为one-click attack或者session riding,通常缩写为CSRF或者XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。

《Flask Web开发》笔记——第四章 Web表单_第1张图片
CSRF攻击原理

CSRF攻击原理:

  • 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;
  • 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
  • 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
  • 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
  • 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。
    由此可见,CSRF攻击的本质就是第三方网站利用浏览器保存的Cookie信息,获取了对被攻击网站的操作权限,此时第三方软件就能够像该用户一样操作该网站。
    因此,跨站请求伪造保护的作用就是,阻断第三方来源对Cookie信息的利用。其方法主要有如下几种:
    《Flask Web开发》笔记——第四章 Web表单_第2张图片
    防御CSRF攻击

    这里只是对CSRF作一个一般性的了解,好在默认状态下, Flask-WTF 能保护所有表单免受跨站请求伪造的攻击。为了实现 CSRF 保护, Flask-WTF 需要程序设置一个密钥。 Flask-WTF 使用这个密钥生成加密令牌,再用令牌验证请求中表单数据的真伪。其方法如下hello.py代码:
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'

app.config 字典可用来存储框架、扩展和程序本身的配置变量。使用标准的字典句法就能把配置值添加到 app.config 对象。后面还会了解到,这个字典的值,还可以从文件中或环境变量中获得。

4.2 表单类

使用 Flask-WTF 时,每个 Web 表单都由一个继承自 Form 的类表示。这个类定义表单中的一组字段,每个字段都用对象表示。字段对象可附属一个或多个验证函数。验证函数用来验证用户提交的输入值是否符合要求。
这是原文的第一段,这段话包含了如下的几层意思:

  • 使用Flask-WTF时,web表单是一个类,这个类的基类是Form类。所以,我们在操作web表单的时候,既需要考虑来自基类的属性和方法,也需要考虑本身的属性和方法。

  • 这个类定义了一组字段。我们来看看这组字段,如下表所示,这些字段规定了表单中输入内容的格式,如文本字段,密码类型字段等等。或表单本身具有的一些格式,如表单的提交按钮,下拉列表格式等等。


    《Flask Web开发》笔记——第四章 Web表单_第3张图片
    WTForms支持的HTML标准字段
  • 字段对象可以附属验证函数,验证函数是用于确认表单中输入的内容是否复合要求。


    《Flask Web开发》笔记——第四章 Web表单_第4张图片
    WTForms验证函数

    我们以如下的hello.py为例子来说明字段的作用:

from flask-wtf import FlaskForm
from wtforms import StringField, SubmitField
for wtforms.validators import Required

class NameForm(Form):
    name = StringField('What is your name?', validators=[Required()])
    submit = SubmitField('Submit')

在这里,StringField是文本字段,表示在这里的输入必须是文本。可以看到,这个字段湖面的括号里面还有一些参数,其中可选参数validators指定一个由验证函数组成的列表,在接受用户提交的数据之前验证数据。验证函数Required()确保提交的字段不为孔。而SubmitField表单提交按钮。

4.3 把表单渲染成HTML

如果在视图函数中,一个NameForm的实例通过参数form传入模板,可以在模板中生成表单,这个表单还可以把参数传入渲染字段的函数。例如:

{{ form.hidden_tag() }} {{ form.name.label }} {{ form.name(id='my-text-field') }} {{ form.submit() }}

但是这个方式虽然指定了HTML属性,但是工作量非常大,你需要一项项去详细的渲染你的表单。所以,如果没有特别的需求,最好利用Bootstrap中的表单样式。
Flask-Bootstrap的使用很简单,可以使用预先定义好的表单样式渲染整个Flask-WTF表单,如下:

{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}

import 指令的使用方法和普通 Python 代码一样,允许导入模板中的元素并用在多个模板中。导入的 bootstrap/wtf.html 文件中定义了一个使用 Bootstrap 渲染 Falsk-WTF 表单对象的辅助函数。 wtf.quick_form() 函数的参数为 Flask-WTF 表单对象,使用 Bootstrap 的默认样式渲染传入的表单。

4.4 在视图函数中处理表单

@app.route('/', methods=['GET', 'POST'])
def index():
    name = None
    form = NameForm()
    if form.validate_on_submit():
        name = form.name.data
        form.name.data = ''
    return render_template('index.html', form=form, name=name)

视图函数需要渲染表单和接收表单的数据。如上面的index()视图函数版本,form是实例化的NameForm类,通过render_template函数传递给模板index.html,对于模板的渲染的其他参数也传递给模板。

4.5 重定向和用户会话

重定向是一种特殊的响应, 响应内容是 URL,而不是包含 HTML 代码的字符串。浏览器收到这种响应时, 会向重定向的 URL 发起 GET 请求,显示页面的内容。
但这种方法会带来另一个问题。 程序处理 POST 请求时,使用 form.name.data 获取用户输入的名字,可是一旦这个请求结束,数据也就丢失了。因为这个 POST 请求使用重定向处理,所以程序需要保存输入的名字, 这样重定向后的请求才能获得并使用这个名字,从而构建真正的响应。
程序可以把数据存储在用户会话中,在请求之间“ 记住”数据。用户会话是一种私有存储,存在于每个连接到服务器的客户端中。
默认情况下,用户会话保存在客户端 cookie 中,使用设置的 SECRET_KEY 进
行加密签名。 如果篡改了 cookie 中的内容,签名就会失效,会话也会随之失效。
如下为实现重定向和用户会话的hello.py

from flask import Flask, render_template, session, redirect, url_for
@app.route('/', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():
        session['name'] = form.name.data
        return redirect(url_for('index'))
    return render_template('index.html', form=form, name=session.get('name'))

url_for() 函数的第一个且唯一必须指定的参数是端点名,即路由的内部名字。
redirect() 是个辅助函数,用来生成 HTTP 重定向响应。
使用 session.get('name') 直接从会话中读取 name 参数的值

你可能感兴趣的:(《Flask Web开发》笔记——第四章 Web表单)