Web开发——Flask框架

Flask框架——Flask-WTF表单:数据验证、CSRF保护

2022-07-22  本文已影响0人  白巧克力LIN

上篇文件中,我们学习了Flask框架——消息闪现,这篇文章我们学习Flask框架——Flask-WTF表单:数据验证、CSRF保护。

Flask-WTF

表单负责收集网页中的数据,是Web应用程序的基本功能。

Flask-WTF是Flask框架的一个扩展,用来处理表单,它封装了WTForms,其特点有:

在WTForm表单中,主要的功能有验证用户提交的数据合法性、快速渲染模板、CSRF保护、文件上传和验证码等。

其安装方式很简单,执行如下代码即可:

pip install flask-wtf

在安装flask-wtf的过程中,系统会自动安装wtform。

WTForms

表单字段

WTforms包中包含各种表单字段的定义,WTForms支持HTML的字段有:

字段 说明
BooleanField 复选框,值为True或False,相当于HTML的<input type ='checkbox'>
DateField 文本字段, 值为datetime.date格式
DateTimeField 文本字段, 值为datetime.datetime格式
IntegerField 文本字段, 值为整数
DecimalField 用于显示带小数的数字的文本字段,值为decimal.Decimal
FloatField 文本字段, 值为浮点数
RadioField 一组单选框
FileField 文件上传字段
SelectField 下拉列表
SelectMultipleField 下拉列表, 可选择多个值
SubmitField 表单提交按钮,相当于HTML的<input type="submit">
StringField 文本字段,相当于HTML的<input type="text">
TextAreaField 多行文本字段,相当于HTML的<input type="textarea">
HiddenField 隐藏文本字段,相当HTML的<input type="hidden">
FormFiled 把表单作为字段嵌入另一个表单
FieldList 子组指定类型的字段
PasswordField 密码文本字段,相当于HTML的<input type = 'password'>

validators验证器

WTForms支持的validators验证器有:

验证函数 说明
Email 验证是电子邮件地址
EqualTo 比较两个字段的值; 常用于要求输入两次信息进行确认的情况
IPAddress 验证IPv4网络地址
Length 验证输入字符串的长度
NumberRange 验证输入的值在数字范围内
Optional 无输入值时跳过其它验证函数
DataRequired 确保字段中有数据
Regexp 使用正则表达式验证输入值
URL 验证url
AnyOf 确保输入值在可选值列表中
NoneOf 确保输入值不在可选列表中

注意:在使用上面的WTForms表单支持的HTML字段与验证函数之前,需要导入这些HTML字段与验证函数

好了,了解了WTForms表单支持的HTML字段与验证函数后,接下来我们通过示例代码来演示表单数据验证。

数据验证

创建一个Flask项目并在项目中创建一个名为form.py的表单类文件,当然文件名可以是任意的,在form.py文件中写入以下代码:

from flask_wtf import FlaskForm                     #导入FlaskForm
from wtforms import StringField, PasswordField      #导入需要的字段
from wtforms.validators import DataRequired, length     #导入需要的验证函数

class MyForm(FlaskForm):
    name = StringField('name', validators=[DataRequired()]) #使用文本字段,数据不能为空验证
    password=PasswordField('password',validators=[DataRequired(),length(min=6,max=12)]) #使用密码文本字段,length长度验证

导入我们需要的FlaskForm、字段与验证函数,这里我们使用了StringField、PasswordField字段和DataRequired数据不能为空验证函数、length长度验证函数。

当然我们可以在字段中添加多个验证函数,只需要在validators验证器中添加验证函数即可,例如:将name = StringField('name', validators=[DataRequired()])代码改为:

    name = StringField('name', validators=[DataRequired(),length(min=2,max=6)])

表单类文件已经写好了,接着在templates目录下创建一个名为form的html文件,然后在Flask项目的app.py文件中编写视图函数,代码如下所示:

from flask import Flask, render_template
from form import MyForm

app = Flask(__name__)

@app.route('/')
def user_form():
    myform=MyForm()     #创建表单类对象
    if myform.validate_on_submit():             
        return '提交成功'
    return render_template('form.html',myform=myform)   #渲染form.html,并将myform表单对象传到form.html中

if __name__ == '__main__':
    app.run()

导入必要的包与库,在视图函数中创建刚才编写的表单类对象myform,validate_on_submit()方法检查是否是一个POST请求并且请求是否有效,再通过render_template()方法渲染form.html文件,并将myform传入form.html中。

app.py文件中的视图函数已经写好了,接下来编写刚才创建的form.html文件,其文件代码如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {#创建表单#}
    <form action="" method="post">
        <p>{{ myform.name }}</p>
        <p>{{ myform.password }}</p>
        <p>{{ myform.submit }}</p>
    </form>
</body>
</html>

在form.html文件中,我们通过{{ 表单类对象.属性 }}的方式渲染表单字段,当我们表单类字段定义中传入label参数时,还可以在模板文件中通过{{ 表单类对象.属性.label }}渲染该字段的label文本。

是不是这样就可以了呢,我们运行Flask项目,浏览器访问http://127.0.0.1:5000/,发现报了如下错误:

RuntimeError: A secret key is required to use CSRF.     #运行时错误:使用CSRF需要密钥

这时我们只需要在配置中添加SECRET_KEY即可,代码如下所示:

app.config['SECRET_KEY']='hakhfaskh'        #SECRET_KEY值是任意的

重新启动Flask项目并浏览http://127.0.0.1:5000/就不会报错了,如下图所示:


当我们没输入信息并按提交时,系统会自动提示浏览器内置的错误提示。

观察其源码,可以发现可以发现WTForm表单字段的第一个参数为表单的id和name的值。

自定义验证

一般来说,如果对表单有额外需要的验证,一般自定义表单的额外的验证方法而不是重新自定义新的字段,我们可以通过form.py表单类中使用validate_<fieldname>自定义验证,示例代码如下所示:

def validate_name(self,data):       #为name添加自定义validata_%s,并传入输入值data
    if self.name.data[0].isdigit():     #使用isdigit检验是否为数字开头,使用data[0]获取数据的首位
        raise ValidationError('用户名不能以数字开头')     #若验证不通过则抛出异常

这里我们为form.py表单类中的name添加自定义验证,所以自定义函数名为validate_name,如果我们为表单类中的password添加自定义验证时,自定义函数名为validate_password,也就是说自定义验证函数名要和表单类中字段名要对应。

这里我们为用户名添加了首字母不能以数字开头的验证,启动flask项目,并访问http://127.0.0.1:5000/,如下图所示:

CSRF保护

在上面的操作中,还没使用CSRF保护,在使用CSRF保护前,我们先了解一下CSRF的一些知识。

CSRF:跨站点请求伪造(Cross—Site Request Forgery),跟XSS攻击一样,存在巨大的危害性。

简单来说就是黑客盗用了你的身份,以你的名义发送恶意请求,服务器不知道是黑客请求的,服务器认为是你本人发出的请求。

其攻击原理如下图所示:


用户小明通过输入用户名、密码登录某安全网站A,网站服务器通过验证信息返回cookie给用户的浏览器,在未退出网站A或删除cookie期间,小明浏览了某不良网站B,不良网站B攻击代码来获取你安全网站A的cookie值并访问网站A,由于黑客拥有小明网站A的cookie,就可以以小明的身份访问网站A,以小明的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等操作。

很多网络诈骗是CSRF攻击,所以大家不要随便点击不明来路的链接和不要浏览不良网站。

那么如何防御CSRF攻击呢?

在Flask项目中,使用CSRFProtect()方法启动全局启用CSRF保护,代码如下所示:

from flask import Flask, render_template
from flask_wtf import CSRFProtect
from form import MyForm

app = Flask(__name__)
app.config['SECRET_KEY']='hakhfaskh'
#启动CSRF保护
csrf = CSRFProtect(app)

@app.route('/',methods=['GET','POST'])
def hello_world():
    myform=MyForm()     #创建表单类对象
    return render_template('form.html',myform=myform)

if __name__ == '__main__':
    app.run()

CSRF保护需要一个密钥,CSRF默认是使用配置的SECRET_KEY值,当然我们还可以单独使用WTF_CSRF_SECRET_KEY来设置。

在HTML文件中,我们需要渲染csrf_token或使用<input type="hidden"来隐藏csrf_token代码如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <form action="" method="post">
        {{ myform.csrf_token }}         {#渲染csrf_token#}
        {# 使用<input type="hidden"隐藏csrf_token#}
{#        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>#}
        <p>{{ myform.name }}</p>
        <p>{{ myform.password }}</p>
        <p>{{ myform.submit }}</p>
    </form>
</body>
</html>

这样就成功使用了CSRF保护,启动Flask项目并访问http://127.0.0.1:5000/,如下图所示:


当我们在网站中表单中填写信息会携带隐藏值提交给服务器,服务器根据隐藏值和用户填写的信息返回cookie值给用户,而cookie值没有隐藏值的信息,即使黑客获取到我们的cookie值,但无法获取隐藏值,没有隐藏值就无法得到服务器的信息验证。从而实现了CSRF保护、数据安全。

好了,关于Flask框架——Flask-WTF表单:数据验证、CSRF保护就讲到这里了,感谢观看,下篇文章学习Flask框架——Flask-WTF表单:文件上传、验证码。
公众号:白巧克力LIN

该公众号发布Python、数据库、Linux、Flask、自动化测试、Git等相关文章!

上一篇下一篇

猜你喜欢

热点阅读