Flask中的内部重定向

13

简而言之:

只使用 Flask 微框架(和其依赖项),我们可以从一个路由内部重定向到另一个路由?

例如:

  1. 用户提交注册表单(包括usernamepassword)到 @app.route('/register', methods=['POST'])
  2. 如果注册成功,Flask 自动执行 HTTP POST 请求到@app.route('/login', methods['POST'])并传递usernamepassword
  3. 处理并登录用户

细节:

我正在使用Flask 框架Flask-JWT扩展来构建 REST API。更具体地说,我正在实现登录和注册功能。

登录功能完美运行,并返回一个 JSON 对象令牌。

以下是我的(登录)身份验证处理程序(即/auth (POST 请求) - 默认的 Flask-JWT 身份验证URL规则):

@jwt.authentication_handler
def authenticate(username, password):
    user = User.query.filter_by(username=username).first()
    if user and user.verify_password(password):
        return user
    return None

成功的登录将返回:

{
  "token": "<jwt-token>"
}

以下是我的注册流程:

@app.route('/register', methods=['PUT'])
def register():
    username = request.form.get('username')
    password = request.form.get('password')
    if username is None or password is None:
        abort(400)  # missing parameters

    user = User.query.filter_by(username=username).first()
    if user:
        abort(400)  # user exists
    else:
        user = User(user=user)
        user.hash_password(password)
        db.session.add(user)
        db.session.commit()

        # How do we generate a token?
        # Perform an internal redirect to the login route?

    return jsonify({'token': <jwt-token>}), 201

我认为你无法使用POST数据进行重定向...否则你可能只需要查看flask.redirect... - Joran Beasley
我认为你所说的“内部重定向”是指通过设置一个虚假的外部请求,从路由表中调用注册(register())函数中的登录功能。与其回答那个问题,我想指出在Flask中可以调用非路由的Python子程序。因此,你可以编写一个子程序并从两个不同的路由调用它,这更加直接简单。顺便说一下,在允许新用户登录之前,向其电子邮件地址发送确认邮件以请求确认是很常见/正常的做法。 - Craig Hicks
1个回答

9

您应该使用Post-Redirect-Get模式。

from flask import Flask, redirect, request, render_template
app = Flask("the_flask_module")

@app.route('/', methods=["GET", "POST"])
def post_redirect_get():
    if request.method == "GET":
        return render_template("post_redirect_get.html")
    else:
        # Use said data.
        return redirect("target", code=303)

@app.route("/target")
def target():
    return "I'm the redirected function"

app.run(host="0.0.0.0", port=5001)

如果您想将数据传递给目标函数(例如令牌),则可以使用会话对象将其存储

因此,它可以分解为以下内容:

@app.route('/register', methods=['PUT'])
def register():
    username = request.form.get('username')
    password = request.form.get('password')
    if username is None or password is None:
        abort(400)  # missing parameters

    user = User.query.filter_by(username=username).first()
    if user:
        abort(400)  # user exists
    else:
        user = User(user=user)
        user.hash_password(password)
        db.session.add(user)
        db.session.commit()

        # How do we generate a token?
        redirect("login_success", code=307)

@app.route("login_success", methods=["GET", "POST"])
@jwt_required()
def login_success():
    return "Redirected Success!"

编辑: 我之前没有使用过Flask-JWT,也不知道需要进行post请求。但是你可以告诉Flask使用当前方法进行重定向(而不是get请求),通过传递重定向函数code=307希望这能解决您的扩展问题。


它完美地回答了我的简短问题。但不幸的是,在Flask-JWT的上下文中,它无法工作,因为该扩展在一个POST路由中处理身份验证响应(或者至少我无法通过此扩展使其正常工作)。 - grim
1
我不同意这个答案回答了“我们是否可以从一个路由内部重定向到另一个路由”的问题,我认为这显然意味着在两者之间不向客户端提供响应。你的代码确实向客户端返回了响应。你的代码肯定是标准/最佳的方法,我相信你知道原因:为了防止重复提交表单[Grinberg,Miguel。Flask Web Development:使用Python开发Web应用程序(第44页)。O'Reilly Media. Kindle版。],“内部重定向”一词存在很多混淆。 - Craig Hicks
@CraigHicks 这确实是一个有力的批评。如果您有一种无需客户端响应即可重定向的方法(不会破坏SSL安全性、DNSec或需要特殊的JavaScript来重新加载新资源),我肯定会倾听。 - AlexLordThorsen

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