Flask登录 vs. Apache缓存

3

我是一名初学者的 Web 开发者,但是我有着丰富的 Python 编程经验和 Apache 服务器使用经验。最近,我在试着搭建一个小型网站,并通过学习 Flask、HTML 模板等内容来解决一些托管问题。

我跟随了几个 Flask 教程,在受到访问控制的端点上使用了 @login_required 装饰器来控制页面访问权限,并使用 session 存储已登录的键值对。这在本地运行 Flask 开发服务器时完美运行,但是当我将其部署到托管服务上时,很多被访问控制的端点似乎都被缓存,导致即使我注销登录(并检查会话数据以确保键已删除),我仍然可以看到它们。

以下是一些具体情况:

  • 使用 flasksession 存储登录信息,而不是使用 Flask-Login。

  • 托管在使用 Phusion Passenger 作为 Apache WSGI 接口的托管 VPS 上。

  • 目前没有使用任何 Apache 配置文件...只是默认设置。

  • 该网站流量非常低…… 可能现在只有我和机器人访问。 :)

我的 passenger_wsgi 文件:

import sys, os
from datetime import timedelta
INTERP = "/home/<website>/venv1/bin/python3"
#INTERP is present twice so that the new Python interpreter knows the actual executable path
if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)

# def application(environ, start_response):
#     start_response('200 OK', [('Content-type', 'text/plain')])
#     return ["Hello, world!"]

sys.path.append(os.getcwd())
from app import app as application

登录后,一切正常。但在注销之后,我仍然可以访问那些应该受到访问控制的端点,并且每次检查浏览器的网络流量时都能看到这样的“证据”:

Summary
URL: https://<website>/<endpoint>  <---- an endpoint covered by @login_required
Status: 200
Source: Memory Cache

Request
No request, served from the memory cache.

Response
Content-Type: text/html; charset=utf-8
Expires: Wed, 22 Dec 2021 17:14:00 GMT
Date: Wed, 22 Dec 2021 17:04:00 GMT
Content-Length: 23
Cache-Control: max-age=600
Vary: User-Agent
Status: 200 OK
x-powered-by: Phusion Passenger 5.0.30
Server: Apache

所以我的问题是...
  1. 我的诊断是否正确,这是Apache缓存在起作用?(证据看起来很有说服力...:))
  2. 我目前不想投入精力转移到flask-login,除非它是治疗性的。
  3. 有没有一种简单的方法来控制这种行为,而不需要成为Apache或Passenger配置文件的专家之类的人?如果这个低流量网站可以做到,我不介意关闭缓存,但我会对一个好的解决方案感兴趣,以便教育自己如何控制缓存或某种方式告诉Apache哪些端点受到访问控制。
我谦虚地向处理这些技术栈的人提交我的问题!

您确认在用户注销时从会话集合中弹出k-v吗?另一种解决方法是在用户登录之前清除会话。 - Harry Duffy
看起来你正在从浏览器缓存中获取响应。为了确认,请尝试注销,清除浏览器缓存,然后尝试访问该URL。 - Gonzalo Odiard
1
你尝试给这些特定路由的响应添加无缓存头吗? 等待回复中... - Dev
我非常确定这是缓存的问题。通常response.cache_controlafter_request中设置。例如:https://dev59.com/f2Ag5IYBdhLWcg3w1t_y#23115561 - 但是要禁用缓存,请使用其他缓存控制设置:https://dev59.com/jWMl5IYBdhLWcg3wwZPc - VPfB
如果你的应用程序即使不缓存也不会降低性能,那么像这个讨论中所述,禁用它怎么样?这样,每次请求都需要实时处理。 - Bilal Qandeel
显示剩余3条评论
1个回答

0

从5.0版本开始,Passenger会自动为被认为可缓存的响应添加cache-control头信息

为了避免这种情况发生,您的应用应该添加Cache-Control: no-store头信息

在Flask中全局进行配置,可以参考这里的描述

@app.after_request
def add_header(response):
    # response.cache_control.no_store = True
    if 'Cache-Control' not in response.headers:
        response.headers['Cache-Control'] = 'no-store'
    return response

如果你想更具有辨别力,只想针对需要登录的路由执行此操作,你可以创建自己的扩展来扩展 login_required 装饰器,以便针对需要登录的路由执行此操作(或者完全使用一个单独的装饰器)

from flask import make_response
from flask_login import login_required as _login_required

def login_required(f):
    # apply the usual login_required decorator
    decorated = _login_required(f)
    def cache_no_store_login_required_view(*args, **kwargs):
        resp = make_response(decorated(*args, **kwargs))
        # add the cache-control header to the response
        resp.headers['Cache-Control'] = 'no-store'
        return resp
    return cache_no_store_login_required_view

或者作为一个单独的装饰器来设置不存储...

from functools import wraps
def cache_no_store(f):
    @wraps(f)
    def decorated_view(*args, **kwargs):
        resp = make_response(f(*args, **kwargs))
        resp.headers['Cache-Control'] = 'no-store'

@app.route('/protected')
@cache_no_store
@login_required
def my_route():
    # ...

以上的评论很中肯,但这是一个很好的全面解释。谢谢。 - AirSquid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接