Python Flask: отслеживание пользовательских сеансов? Как получить идентификатор сеанса cookie?

Я хочу создать простой webapp как часть моей учебной деятельности. Предполагается, что Webapp попросит пользователя ввести свой email_id, если он встречает первого посетителя, и он запоминает пользователя через файл cookie и автоматически регистрирует его/ее для выполнения функций.

Это мой первый раз с созданием пользовательского веб-приложения. У меня есть синий шрифт, но я не могу понять, как его реализовать. В первую очередь я путаюсь в отношении способа сбора cookie пользователя. Я изучил различные учебники и flask_login, но я думаю, что то, что я хочу реализовать, намного проще, чем реализация flask_login.

Я также попытался использовать 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'))

Ответ 1

Вы можете получить доступ к куки файлам запроса через словарь 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'))

СУШКА КОДА

Теперь вы заметите, что в методах home и do_that много шаблонов, связанных с do_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)

Используя то, что предоставлено

Если вам не нужен файл cookie с определенным именем, я бы порекомендовал использовать flask.session поскольку в него уже flask.session много flask.session (он подписан, поэтому его нельзя подделать, его можно установить как HTTP). только и т.д.). Это СУШИТ наш декоратор 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'])