2016-03-28 32 views
6

有关处理“下一个”URL的文档Flask-login。这个想法似乎是:如何通过使用Flask和Flask登录的“下一个”URL?

  1. 用户进入/some-secret-URL
  2. 用户被重定向到登录页面(如/login
  3. 成功登录后,用户被重定向回/some-secret-URL

我找到的唯一使用Flask登录的半完整示例是https://gist.github.com/bkdinoop/6698956。这很有帮助,但由于它不包含HTML模板文件,因此我看到我是否可以将它们重新创建为自我训练练习。

这里的/secret/login部分的简化版本:

@app.route("/secret") 
@fresh_login_required 
def secret(): 
    return render_template("secret.html") 

@app.route("/login", methods=["GET", "POST"]) 
def login(): 
    <...login-checking code omitted...> 
    if user_is_logged_in: 
     flash("Logged in!") 
     return redirect(request.args.get("next") or url_for("index")) 
    else: 
     flash("Sorry, but you could not log in.") 
     return render_template("login.html") 

而这里的login.html

<form name="loginform" action="{{ url_for('login') }}" method="POST"> 
Username: <input type="text" name="username" size="30" /><br /> 
Password: <input type="password" name="password" size="30" /><br /> 
<input type="submit" value="Login" /><br /> 

现在,当用户访问/some-secret-URL,他被转到/login?next=%2Fsecret。到目前为止,这么好 - 查询字符串中的“next”参数。

但是,当用户提交登录表单时,他将被重定向回索引页面,而不是返回到/secret URL。

我猜的原因是因为传入网址上可用的“下一个”参数没有合并到登录表单中,因此在处理表单时没有作为变量传递。 ?解决这个正确的方式

一个解决方案似乎工作 - 从

<form name="loginform" action="{{ url_for('login') }}" method="POST"> 

<form>标签更改为:

<form name="loginform" method="POST"> 

删除“action”属性后,浏览器(至少Windows上的Firefox 45)会自动使用当前URL,使其继承?next=%2Fsecret查询字符串,该查询字符串已成功将其发送到表单处理处理程序。

但省略了“action”表单属性并让浏览器将其填充到正确的解决方案中吗?它是否适用于所有浏览器和平台?

或者Flask或Flask-login打算以不同的方式处理它?

+0

当你把'action =“{{url_for('login')}}”'的HTML源代码输出到底是什么? –

+0

http://flask.pocoo.org/snippets/63/ – davidism

+0

@K DawG,它是'

' –

回答

4

如果您需要在表单中指定不同的动作属性,则不能使用由Flask-Login提供的下一个参数。无论如何,我建议将端点而不是URL放入url参数中,因为它更容易验证。以下是我正在处理的应用程序中的一些代码,也许这可以帮助您。

覆盖烧瓶登录的未经授权的处理程序使用的终端,而不是URL中的下一个参数:

@login_manager.unauthorized_handler 
def handle_needs_login(): 
    flash("You have to be logged in to access this page.") 
    return redirect(url_for('account.login', next=request.endpoint)) 

使用request.endpoint在自己的网址,太:

{# login form #} 
<form action="{{ url_for('account.login', next=request.endpoint) }}" method="post"> 
... 
</form> 

重定向到端点下一个参数(如果存在且有效),否则重定向到后备。

def redirect_dest(fallback): 
    dest = request.args.get('next') 
    try: 
     dest_url = url_for(dest) 
    except: 
     return redirect(fallback) 
    return redirect(dest_url) 

@app.route("/login", methods=["GET", "POST"]) 
def login(): 
    ... 
    if user_is_logged_in: 
     flash("Logged in!") 
     return redirect_dest(fallback=url_for('general.index')) 
    else: 
     flash("Sorry, but you could not log in.") 
     return render_template("login.html") 
+0

在我使用的表单中:next = request.args.get(“next”)。在redirect_dest中,它应该是dest = request.args.get(“next”) – 2ni

+0

@ 2ni在我的例子中,表单显示在每一页的顶部,如果你想要一个单独的登录页面,你应该使用'next = request。 args.get( “下一步”)'。修正你的第二个提到,谢谢。 – timakro

0

@timakro提供了一个整洁的解决方案。 如果你想处理一个动态链接如

指数/ <用户>

然后使用Request的,而不是因为request.endpoint将不包含动态vairable信息:

@login_manager.unauthorized_handler 
def handle_needs_login(): 
    flash("You have to be logged in to access this page.") 
    return redirect(url_for('account.login', next=request.path)) 

以下代码应更改为:

def redirect_dest(home): 
    dest_url = request.args.get('next') 
    if not dest_url: 
     dest_url = url_for(home) 
    return redirect(dest_url) 

@app.route("/login", methods=["GET", "POST"]) 
def login(): 
    ... 
    if user_is_logged_in: 
     flash("Logged in!") 
     return redirect_dest(home=anyViewFunctionYouWantToSendUser) 
    else: 
     flash("Sorry, but you could not log in.") 
     return render_template("login.html")