Flask 中的 Session 和 Cookies、wtforms

发布于:2024-07-07 ⋅ 阅读:(39) ⋅ 点赞:(0)

Flask 中的 Session 和 Cookies

在构建 web 应用时,管理用户的状态和数据是至关重要的。Flask,作为一个灵活的微型 web 框架,提供了会话(Session)和 Cookies 管理的能力。本文将深入探讨 Flask 中的会话和 Cookies 的概念、工作机制以及应用实例,为读者提供全面而详细的理解。

会话和 Cookies 的基本概念

Cookies

  • 定义:Cookies 是服务器存储在用户浏览器上的小片段数据,每次浏览器向服务器发送请求时都会附带这些数据。
  • 用途:主要用于记住用户信息(如登录状态)、跟踪用户访问模式等。

会话(Session)

  • 定义:会话是一种在服务器上存储用户数据的方式,用于跨请求保持状态。
  • 用途:常用于存储用户特定的信息,如登录后的用户ID、购物车内容等。

Cookies 的使用

在 Flask 中操作 Cookies 是非常简单直观的。

设置 Cookies

from flask import Flask, make_response

app = Flask(__name__)

@app.route('/set_cookie')
def set_cookie():
    response = make_response('Cookie has been set')
    response.set_cookie('username', 'John Doe')
    return response

获取 Cookies

from flask import request

@app.route('/get_cookie')
def get_cookie():
    username = request.cookies.get('username')
    return 'The username in cookie is: ' + str(username)

Cookies 的局限性

  • 存储在用户浏览器端

,因此容易受到安全攻击,如跨站脚本(XSS)和跨站请求伪造(CSRF)。

  • Cookies 的大小通常限制在 4KB 左右,不适合存储大量数据。

Flask 会话(Session)的使用

会话(Session)在 Flask 中用于存储在服务端的用户数据,而浏览器只保存一个会话ID的 Cookie。

配置 Flask 会话

在 Flask 应用中,需要设置一个密钥来加密会话数据。

app = Flask(__name__)
app.secret_key = 'your_secret_key'  # 应为难以猜测的密钥

设置会话数据

from flask import session

@app.route('/login')
def login():
    session['user_id'] = '123456'  # 假设用户ID为123456
    return 'User logged in'

获取会话数据

@app.route('/profile')
def profile():
    user_id = session.get('user_id')
    if not user_id:
        return 'Not logged in!', 403
    return 'Profile page for user {}'.format(user_id)

会话的有效期

默认情况下,Flask 的会话是浏览器关闭时过期。也可以设置会话的持续时间:

from datetime import timedelta

app.permanent_session_lifetime = timedelta(days=5)
session.permanent = True  # 使当前会话持久化

会话与 Cookies 的安全性

安全性是管理会话和 Cookies 时必须考虑的重要因素。

安全实践

  • 使用 HTTPS 来防止会话被窃听。
  • 设置 Cookie 的 secure 标志,使其仅通过 HTTPS 发送。
  • 设置 Cookie 的 HttpOnly 标志,阻止 JavaScript 访问 Cookie。
  • 定期更换 secret_key
  • 对敏感数据进行加密处理。

使用 Flask-Session 扩展

对于需要更复杂会话管理的应用,可以使用 Flask-Session 扩展,它支持将会话数据保存在服务器端的多种后端中,例如 Redis、文件系统等。

flask-session

# 1 第三方 flask-session,可以把session的内容保存在服务端
	-redis
    -数据库
    -文件。。。
    
# 2 安装并使用
pip3 install flask-session

第一种

from flask_session.redis import RedisSessionInterface
import redis
app = Flask(__name__)
app.secret_key='adsfasdfads'
conn=redis.Redis(host='127.0.0.1',port=6379)
# 1 client:redis链接对象
# 2 key_prefix:放到redis中得前缀
# 3 use_signer:是否使用secret_key 加密
# 4 permanent:关闭浏览器,cookie是否失效
# 5 生成session_key的长度
app.session_interface=RedisSessionInterface(app,client=conn,key_prefix='session',use_signer=True, permanent=True, sid_length=32)

第二种(推荐)

from flask import Flask,session
from flask_session import Session
from redis import Redis
app = Flask(__name__)
app.secret_key='asdfasdf'
app.debug=True


# 配置信息,可以写在 配置文件中
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = Redis(host='127.0.0.1', port='6379')
# app.config['SESSION_KEY_PREFIX'] = 'lqz'  # 如果不写,默认以:SESSION_COOKIE_NAME 作为key
# app.config.from_pyfile('./settings.py')

Session(app)  # 核心跟第一种方式一模一样
  • app.py

from flask import Flask, session
from flask_session.redis import RedisSessionInterface
import redis

app = Flask(__name__)
conn = redis.Redis(host='127.0.0.1', port=6379)
# use_signer是否对key签名
app.session_interface = RedisSessionInterface(conn, key_prefix='lqz')


@app.route('/')
def hello_world():
    session['name'] = 'jing'
    return 'Hello World!'

@app.route('/index')
def index():
    res = session['name']

    return 'Hello World!' + res

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

  • settings.py

from redis import Redis

SESSION_TYPE = 'redis'
SESSION_REDIS = Redis(host='127.0.0.1', port='6379')

wtforms

​ 在Flask中,WTForms库主要用于处理Web表单的创建、验证和渲染。具体来说,WTForms在Flask中有以下几个关键用途:

  1. 表单验证:
    • WTForms提供了丰富的验证器,如DataRequiredLength等,用于验证用户提交的数据是否符合系统要求。
    • 通过这些验证器,可以确保表单数据的完整性、准确性和安全性。
    • 例如,可以使用DataRequired验证器来确保某个字段(如用户名或密码)必须被填写。
  2. 定义表单字段:
    • WTForms允许用户定义各种类型的表单字段,如文本字段、密码字段、单选按钮、复选框等。
    • 字段的定义与HTML表单元素相对应,使得开发者能够轻松地构建复杂的表单结构。
  3. 渲染表单为HTML:
    • 虽然WTForms本身不直接渲染HTML,但它可以与Flask的模板引擎(如Jinja2)结合使用,将表单渲染为HTML。
    • 这使得开发者能够灵活控制表单的显示样式和布局。
  4. 与Flask框架集成:
    • Flask-WTF是WTForms的Flask扩展,它简化了WTForms在Flask中的使用。
    • Flask-WTF提供了额外的功能,如CSRF保护、文件上传等,增强了表单的安全性。
  5. 自定义验证规则:
    • 除了内置的验证器外,WTForms还支持自定义验证规则。
    • 这使得开发者能够根据自己的业务需求来定义特定的验证逻辑。
  6. 表单继承:
    • WTForms支持表单继承,允许开发者创建基类表单,并在子类中扩展和覆盖字段和验证规则。
    • 这有助于实现代码的重用和模块化。
# pip install WTForms

# django--->forms组件
	-1 校验数据
    -2 错误处理
    -3 渲染页面
    
    
# flask--》第三方的wtforms
  • app.py

from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets

app = Flask(__name__, template_folder='templates')

app.debug = True


class LoginForm(Form):
    # 字段(内部包含正则表达式)
    name = simple.StringField(
        label='用户名',
        validators=[
            validators.DataRequired(message='用户名不能为空.'),
            validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
        ],
        widget=widgets.TextInput(),  # 页面上显示的插件
        render_kw={'class': 'form-control'}

    )
    # 字段(内部包含正则表达式)
    pwd = simple.PasswordField(
        label='密码',
        validators=[
            validators.DataRequired(message='密码不能为空.'),
            validators.Length(min=8, message='用户名长度必须大于%(min)d'),
            validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",
                              message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符')

        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        form = LoginForm()
        return render_template('wtforms_login.html', form=form)
    else:
        form = LoginForm(formdata=request.form)
        if form.validate():
            print('用户提交数据通过格式验证,提交的值为:', form.data)
        else:
            print(form.errors)
        return render_template('wtforms_login.html', form=form)


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

  • wtforms_login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>登录</h1>
<form method="post">
    <p>{{form.name.label}} {{form.name}} {{form.name.errors[0] }}</p>
    <p>{{form.pwd.label}} {{form.pwd}} {{form.pwd.errors[0] }}</p>
    <input type="submit" value="提交">
</form>
</body>
</html>

image-20240614154055809


网站公告

今日签到

点亮在社区的每一天
去签到