我想在学习活动中构建一个简单的Web应用程序。如果遇到首次访问者,Webapp应该要求用户输入他们的email_id,否则它会通过cookie记住用户并自动登录以执行功能。
这是我第一次创建基于用户的Web应用程序。我心中有一个蓝图,但是我无法弄清楚如何实现它。首先,我对收集用户cookie的方式感到困惑。我研究了各种教程和flask_login,但是与flask_login所实现的相比,我想实现的要简单得多。
我也尝试使用,flask.session但是有点难以理解,最终导致实现有缺陷。
flask.session
这是到目前为止我所拥有的(它是基本的,目的是传达我的用例):
`from flask import render_template, request, redirect, url_for
@app.route(“/”, methods= [“GET”]) def first_page(): cookie = response.headers[‘cookie’] if database.lookup(cookie): user = database.get(cookie) # it returns user_email related to that cookie id else: return redirect_url(url_for(‘login’)) data = generateSomeData() # some function return redirect(url_for(‘do_that’), user_id, data, stats)
@app.route(‘/do_that’, methods =[‘GET’]) def do_that(user_id): return render_template(‘interface.html’, user_id, stats,data) # it uses Jinja template
@app.route(‘/submit’, methods =[“GET”]) def submit(): # i want to get all the information here user_id = request.form[‘user_id’]# some data answer = request.form[‘answer’] # some response to be recorded data = request.form[‘data’] # same data that I passed in do_that to keep database.update(data,answer,user_id) return redirect(url_for(‘/do_that’))
@app.route(‘/login’, methods=[‘GET’]) def login(): return render_template(‘login.html’)
@app.route(‘/loggedIn’, methods =[‘GET’]) def loggedIn(): cookie = response.headers[‘cookie’] user_email = response.form[‘user_email’] database.insert(cookie, user_email) return redirect(url_for(‘first_page’))`
你可以通过request.cookies字典访问请求cookie,并通过使用make_response或仅将调用结果存储render_template在变量中然后调用set_cookie响应对象来设置cookie :
request.cookies
make_response
render_template
set_cookie
@app.route("/") def home(): user_id = request.cookies.get('YourSessionCookie') if user_id: user = database.get(user_id) if user: # Success! return render_template('welcome.html', user=user) else: return redirect(url_for('login')) else: return redirect(url_for('login')) @app.route("/login", methods=["GET", "POST"]) def login(): if request.method == "POST": # You should really validate that these fields # are provided, rather than displaying an ugly # error message, but for the sake of a simple # example we'll just assume they are provided user_name = request.form["name"] password = request.form["password"] user = db.find_by_name_and_password(user_name, password) if not user: # Again, throwing an error is not a user-friendly # way of handling this, but this is just an example raise ValueError("Invalid username or password supplied") # Note we don't *return* the response immediately response = redirect(url_for("do_that")) response.set_cookie('YourSessionCookie', user.id) return response @app.route("/do-that") def do_that(): user_id = request.cookies.get('YourSessionCookie') if user_id: user = database.get(user_id) if user: # Success! return render_template('do_that.html', user=user) else: return redirect(url_for('login')) else: return redirect(url_for('login'))
DRYing up the code
现在,你会注意到和方法中有很多样板,所有这些都与登录有关。你可以通过编写自己的装饰器来避免这种情况(如果你想了解更多关于装饰器的信息,请参阅什么是装饰器):homedo_that
from functools import wraps from flask import flash def login_required(function_to_protect): @wraps(function_to_protect) def wrapper(*args, **kwargs): user_id = request.cookies.get('YourSessionCookie') if user_id: user = database.get(user_id) if user: # Success! return function_to_protect(*args, **kwargs) else: flash("Session exists, but user does not exist (anymore)") return redirect(url_for('login')) else: flash("Please log in") return redirect(url_for('login')) return wrapper
然后,你的home和do_that方法变得更短:
# Note that login_required needs to come before app.route # Because decorators are applied from closest to furthest # and we don't want to route and then check login status @app.route("/") @login_required def home(): # For bonus points we *could* store the user # in a thread-local so we don't have to hit # the database again (and we get rid of *this* boilerplate too). user = database.get(request.cookies['YourSessionCookie']) return render_template('welcome.html', user=user) @app.route("/do-that") @login_required def do_that(): user = database.get(request.cookies['YourSessionCookie']) return render_template('welcome.html', user=user)
Using what’s provided
如果你不需要 Cookie来使用特定的名称,我建议你使用flask.session它,因为它已经内置了很多功能(它已签名,因此不能被篡改,可以设置为仅HTTP,等等)。 )。这会使我们的login_required装饰器更加干燥:
login_required
# You have to set the secret key for sessions to work # Make sure you keep this secret app.secret_key = 'something simple for now' from flask import flash, session def login_required(function_to_protect): @wraps(function_to_protect) def wrapper(*args, **kwargs): user_id = session.get('user_id') if user_id: user = database.get(user_id) if user: # Success! return function_to_protect(*args, **kwargs) else: flash("Session exists, but user does not exist (anymore)") return redirect(url_for('login')) else: flash("Please log in") return redirect(url_for('login'))
然后,你的各个方法可以通过以下方式吸引用户:
user = database.get(session['user_id'])