Используем сессии для авторизации

Все любят печеньки

Часто в веб-сервисах возникает необходимость идентифицировать текущего пользователя (т.е., что текущий пользователь - Вася Пупкин, модератор) или получить какую-либо информацию про него (текущий пользователь предпочитает зеленый цвет фона, заходил на сайт 10 раз).

Обычно для этого испольуются cookie файлы. О них мы сегодня и поговорим.

Cookie файлы - это небольшие текстые файлы, которые сайт может хранить в браузере пользователя. Браузер будет присылать их серверу вместе с каждым запросом. В ответе можно попросить браузер что-то удалить или добавить.

С точки зрения программиста бекенда, можно считать, что cookie файлы представляют из себя словарь. Про работу с "чистыми" куками можно почитать здесь.

Но с cookie файлами есть проблема - пользователь может добавлять, изменять, читать и удалять их по своему усмотрению. А значит мы не можем им доверять. Решение этой проблемы - использование сессий!

Сессии - безопасная альтернатива cookie

Сессии - это более безопасные способ хранить данные о пользователе, причем в разных языках этот механизм реализован по разному. Например, сессии в PHP - это когда мы храним данные на сервере, а у пользователя храним только ключ доступа к этим данным.

Во фласке все данные по-прежнему храняться в cookie, но подписываются секретным ключом. Благодаря этому пользователь может посмотреть или удалить данные, но изменить по своему усмотрению уже не может.

С точки зрения программиста, сессия - это словарь, который сохраняет свои значения между запросами пользователя (и в разных функциях).

  1. В начале программы нам нужно задать ключ для подписи cookie файлов и импортировать объект session из библиотеки flask.
from flask import Flask, session

app = Flask(__name__)

# Details on the Secret Key: https://flask.palletsprojects.com/en/1.1.x/config/#SECRET_KEY
app.secret_key = 'BAD_SECRET_KEY'
  1. Когда мы хотим что-то записать о пользователе, мы просто кладем это в словарь session.
session['email'] = "lupa@glavbuh.ru"
  1. А когда хотим получить это обратно - просто берем из словаря session.
email = session.get('email')

P.S. Можно написать и session['email'], но если почты там нет, вылетит ошибка. А метод get просто вернет None и программа продолжит свою работу.

Цветосайт

Ниже пример сервиса, в котором пользователь может выбирать цвет фона для страницы. Цвет мы запонимаем в словаре session.

from flask import Flask, render_template, session, redirect

app = Flask(__name__)
app.secret_key = 'dfdfdf'

@app.route('/')
def index():
    if 'color' in session:
        color = session['color']
    else:
        color = "#FFF"
    return render_template('index.html', color=color)

@app.route('/red')
def red():
    session['color'] = '#F00'
    return redirect('/')

@app.route('/blue')
def blue():
    session['color'] = '#00F'
    return redirect('/')

@app.route('/green')
def green():
    session['color'] = '#0F0'
    return redirect('/')

@app.route('/default')
def green():
    del session['color']
    return redirect('/')

app.run(debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body style="background-color: {{color}};">
    <h1>Цветосайт!</h1>

    <a href="/red">Хочу красный</a><br>
    <a href="/blue">Хочу синий</a><br>
    <a href="/green">Хочу зеленый</a><br>
      <a href="/default">Хочу как обычно</a><br>
</body>
</html>

Авторизация

Для авторизации пользователей в фласке (да и любых сервисах в интернете) используются сессии. Идея в том, что после успешной авторизации (ввода правильного логина и пароля) пользователь получает временный токен, который храниться в cookie файле (в браузере клиента), а на стороне сервера к этому токену привязывается произвольная информация (например, имя пользователя).

Пример использования сессий можно увидеть в коде ниже. В нем при заходе пользователя на страницу входа, мы добавляем в сессию ключ auth, и, если он есть, на главной странице показывается "секретный" текст.

from flask import Flask, session, redirect

# just serve all the static files under root
app = Flask(__name__)
app.secret_key = 'jrfasefasefgj'

@app.route('/')
def index():
    if session.get('auth', False) == True:
        return "<p>Это секретный раздел!</p><p><a href='/logout'>Выйти!</a></p>"
    else:
        return "<p>Вам сюда нельзя!</p><p><a href='/login'>Но можно войти...</a></p>"

@app.route('/login')
def login():
    session['auth'] = True
    return redirect('/')

@app.route('/logout')
def logout():
    session.clear()
    return redirect('/')

(debug=True, port='3000', host='0.0.0.0')