在 Flask 中,除非先访问了另一条路由,否则如何防止访问一条路由?

nes*_*_pp 5 python flask

问题陈述

我正在开发一个在表格中显示项目列表的 Flask Web 应用程序。用户可以选择一行并点击一个Delete按钮来删除该项目。然而,在从数据库中删除项目之前,用户首先被路由到确认屏幕,其中显示了一些项目详细信息以及一个Confirm按钮。确认页面的 url 遵循以下模式:dashboard/confirm-delete/<id>实际删除页面的 url 遵循以下模式:dashboard/delete/<id>。有关admin/views.py更多详细信息,请参见下文。

当系统正常工作时,我遇到的问题是用户可以通过在地址栏中键入 来跳过确认页面dashboard/delete/<id>,其中<id>由实际项目 id 代替。

问题

有没有办法阻止用户访问,dashboard/delete/<id>除非他们先去dashboard/confirm-delete/<id>(确认屏幕)?或者,我的方法是否错误,是否有更好的方法可用?

当前代码:

dashboard.html选择一行并按下删除按钮时调用我页面中的函数:

$('#remove').click(function () {
  var id = getId();
  window.location.href="/dashboard/confirm-delete" + $.trim(id);
  });
Run Code Online (Sandbox Code Playgroud)

确认按钮confirm-delete.html(删除确认页面):

<a class="btn btn-default" href="{{ url_for('admin.delete_item', id=item.id) }}" role="button">Confirm Delete</a> 
Run Code Online (Sandbox Code Playgroud)

我的admins/views.py

@admin_blueprint.route('dashboard/confirm-delete/<id>')
@login_required
@groups_required(['admin'})
def confirm_delete_item(id)
  item = Item.query.get_or_404(id)
  return render_template('admin/confirm-delete.html', item=item, title="Delete Item")

@admin_blueprint.route('dashboard/delete/<id>', methods=['GET', 'POST'])
@login_required
@groups_required(['admin'})
def delete_item(id)
  item = Item.query.get_or_404(id)
  db.session.delete(item)
  db.commit()
  return redirect(url_for('home.homepage'))
Run Code Online (Sandbox Code Playgroud)

解决方案

根据标记为已接受的答案,我解决了以下问题:

首先,我创建了一个新表单来处理页面中的Submit按钮confirm-delete.html

admin/forms.py

from flask_wtf import FlaskForm
from wtforms import SubmitField

class DeleteForm(FlaskForm):
  submit = SubmitField('Confirm')
Run Code Online (Sandbox Code Playgroud)

我将Confirm Button代码替换为以下内容confirm-delete.html

<form method="post">
  {{ form.csrf_token }}
  {{ form.submit }}
</form>
Run Code Online (Sandbox Code Playgroud)

最后,我将这两个函数合并app/views.py如下:

@admin_blueprint.route('dashboard/confirm-delete/<id>', methods=['GET', 'POST'])
@login_required
@groups_required(['admin'})
def confirm_delete_item(id)
  form = DeleteForm()
  item = Item.query.get_or_404(id)
  if form.validate_on_submit():  
    if form.submit.data:
      db.session.delete(item)
      db.commit()
      return redirect(url_for('home.homepage'))
  return render_template('admin/confirm-delete.html', item=item, form=form, title="Delete Item")
Run Code Online (Sandbox Code Playgroud)

这样,用户就不能通过在地址栏中键入特定链接来绕过删除确认屏幕,而且它还简化了代码。

mis*_*ato 2

正如评论中已经提到的,解决问题的一种方法是在用户发送请求时检查某个 cookie。但就我个人而言,我不会推荐这种方法,因为除非您想出某种哈希算法来哈希 cookie 值并以某种方式检查它们,否则此类 cookie 很可能会受到损害。 在我看来,最简单、最安全、最自然的方法是使用 CSRF 令牌
保护路由。/delete您可以使用Flask_WTF扩展来实现它。
总之,你必须创建类似的东西DeleteForm,然后你输入{{form.csrf_token}}你的并confirm-delete.html验证它delete_view()form.validate_on_submit()

查看他们的文档:
http://flask-wtf.readthedocs.io/en/stable/form.html
http://flask-wtf.readthedocs.io/en/stable/csrf.html