首页 > 解决方案 > 如何使用会话来限制对后端的访问,并且只允许管理员在烧瓶中访问它?(Python)

问题描述

我想知道如何使用会话限制对我网站某些页面的访问。总之,我希望管理员通过与普通用户相同的登录表单登录,但使用他输入的凭据,他将被重定向到后端页面,在那里他将拥有对两个前端网页的完全访问权限和后端网页。当用户登录时,他们只能查看前端网页。我试图避免用户登录然后将网络浏览器搜索栏中的 URL 从 127.0.0.7/homepage 更改为 127.0.0.7/backend 并因为他已登录而被允许访问的情况。

我正在使用下面的代码来检查用户是否已登录。如果没有,那么他们将被重定向到登录页面。我正在使用烧瓶框架。非常感谢任何建议。

谢谢你。

app.route('/backend', methods=['POST', 'GET'])
def backend():
if 'userkey' in session:
    # connect to database using pymysql
    if cursor.rowcount == 0:
        return render_template('backend.html', msg="No orders found...")
    else:
        rows = cursor.fetchall()
        return render_template('backend.html', orderdata=rows)

elif 'userkey' not in session:
    return redirect('/login')
else:
    return redirect('/login')

标签: pythonflask

解决方案


用户通过身份验证后,您必须已经在登录视图中设置 session['userkey'],您只需添加有关用户管理状态的附加信息即可使其正常工作。如果您将if 'userkey' in session视图函数之外的所有检查都移到装饰器中,那么它也将容易得多,以便可以轻松地重用它来保护您的所有视图函数。此模式显示在标题“需要登录的装饰器” http://flask.pocoo.org/docs/1.0/patterns/viewdecorators/的烧瓶文档中。

在您的登录功能中,您应该在检索用户密钥和散列密码的同时查询数据库的用户管理员状态。然后简单地设置 session["admin"] = True 如果用户是管理员或者如果他们不是管理员则根本不设置它。

然后,以下代码将适用于装饰器。

from functools import wraps
from flask import session

def login_required(status=None):
    def login_decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            if 'userkey' in session and (status is None or status in session):
                return func(*args, **kwargs)
            else:
                return redirect("/login")
        return wrapper
    return login_decorator

然后应该应用此装饰器来保护您的所有视图功能。然后它将在每个视图函数之前执行,如果所有条件都满足则允许视图继续,如果不满足则将用户重定向回登录页面。它需要一个可选的单个参数状态,在您的情况下,对于所有后端视图应该是“管理员”,并且不应该为不需要管理员权限的前端视图提供。函数内部的 functools.wraps 装饰器只是用来更新包装函数的元数据,以便像这样的属性function.__name__表现如预期。会话检查中的“用户密钥”与您的原始代码中的相同,但我们另外检查是否提供了状态,如果是,则它是否也存储在会话中。在您的情况下,status 的唯一值是“admin”,但可以轻松扩展此模式以允许其他组每个都可以访问网站的不同部分。

假设所有用户检查都在装饰器中执行,您的后端视图功能可以简化为

@app.route('/backend', methods=['POST', 'GET'])
@login_required("admin")
def backend():
    # connect to database using pymysql
    if cursor.rowcount == 0:
        return render_template('backend.html', msg="No orders found...")
    else:
        rows = cursor.fetchall()
    return render_template('backend.html', orderdata=rows)

相同的装饰器可用于保护所有前端视图功能,只需省略“admin”参数。

@app.route('/frontend', methods=['POST', 'GET'])
@login_required()
def frontend():
    # .....

推荐阅读