在Flask中,除非先访问另一条路线,否则如何阻止访问路径?

时间:2017-02-25 01:15:08

标签: python flask

问题陈述

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

虽然系统正常运行,但我遇到的问题是,用户只需在地址栏中输入dashboard/delete/<id>,其中<id>被实际的商品ID替换,就可以跳过确认页面。< / p>

问题

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

当前代码:

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

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

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

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

我的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'))

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

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

admin/forms.py

from flask_wtf import FlaskForm
from wtforms import SubmitField

class DeleteForm(FlaskForm):
  submit = SubmitField('Confirm')

我将Confirm Button代码替换为confirm-delete.html

<form method="post">
  {{ form.csrf_token }}
  {{ form.submit }}
</form>

最后,我合并了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")

这样,用户无法通过在地址栏中键入特定链接来绕过删除确认屏幕,而且还可以简化代码。

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

我会将删除页面设为POST。浏览器可能会跳过GET请求或尝试多次,您无法控制它。抓取工具可以关注匿名删除链接并删除您的所有Wiki文章。浏览器预取程序可以预取注销链接。

REST纯粹主义者会坚持使用GET,POST,DELETE和PUT方法来实现其预期目的。

https://softwareengineering.stackexchange.com/questions/188860/why-shouldnt-a-get-request-change-data-on-the-server

所以,

在HTML中

<form action='/dashboard/delete/{{id}}' method='post'>

在Flask中

@app.route('/dashboard/delete/<int:id>', methods=['POST'])
def delete(id):

答案 2 :(得分:0)

我认为括号有误。 @groups_required(['admin'})

应该吗? @groups_required(['admin'])