2017-02-25 54 views
0

問題陳述在Flask中,除非先訪問另一條路由,否則我該如何防止路由被訪問?

我正在研究一個Flask web應用程序,該應用程序顯示錶中的項目列表。用戶可以選擇一行並按下Delete按鈕來刪除該項目。但是,在從數據庫中刪除項目之前,用戶首先會路由到確認屏幕,其中顯示一些項目詳細信息以及Confirm按鈕。確認頁面的網址遵循以下模式:dashboard/confirm-delete/<id>以及實際刪除頁面的網址遵循以下模式: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); 
    }); 

確認按鈕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')) 

SOLUTION

基於標記的答案,因爲接受我解決了這個問題,如下所示:

首先,我創建了一個新的形式,以處理confirm-delete.htmlSubmit按鈕:

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") 

通過這種方式,用戶不能旁路通過在地址欄中輸入特定鏈接來刪除確認屏幕,並且可以簡化代碼。

+0

我想到的,我會在頁面上設置一個cookie的第一件事,其中刪除按鈕,然後在確認頁面上檢查該cookie。 – coralvanda

回答

0

正如在評論中已經提到的,解決您的問題的一種方式是在用戶發送請求時檢查某個cookie。但個人而言,我不會推薦這種方法,因爲這樣的cookie很可能會受到影響,除非您想出某種散列算法來散列cookie值並以某種方式檢查它們。
在我看來,最簡單,最安全,最自然的方法是使用CSRF令牌保護/delete路由。您可以使用Flask_WTF擴展實現它。
總之,你必須創造這樣DeleteForm,那麼你就把{{form.csrf_token}}confirm-delete.htmlform.validate_on_submit()

退房驗證它在delete_view()他們的文檔:
http://flask-wtf.readthedocs.io/en/stable/form.html
http://flask-wtf.readthedocs.io/en/stable/csrf.html

+0

謝謝你的建議。我用CSRF實現表單驗證的問題是,我仍然不得不以某種方式將'form'對象從一個視圖傳遞到另一個視圖。因此,我決定合併這兩個視圖(最終結果比我最初的方法更好)。我編輯了我的問題以包含我使用的解決方案。謝謝! –

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'> 

在瓶

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

謝謝,這是非常豐富的。我結合了兩個視圖函數,因此我保留了'methods = ['GET','POST']'。 –