Статьи

Создание веб-приложения с нуля с использованием Python Flask и MySQL: Часть 2

В предыдущей части этой серии статей мы увидели, как начать работу с Python Flask и MySQL, и реализовали часть приложения для регистрации пользователей. В этом руководстве мы переходим на следующий уровень, реализуя функции входа и выхода для нашего приложения.

Сначала клонируйте исходный код предыдущего урока из GitHub .

1
git clone https://github.com/jay3dec/PythonFlaskMySQLApp—Part-1.git

После того, как исходный код был клонирован, перейдите в PythonFlaskMySQLApp---Part-1 и запустите сервер.

1
python app.py

Укажите в браузере http: // localhost: 5002, и приложение должно быть запущено.

Перейдите к PythonFlaskMySQLApp---Part-1/templates и создайте новый файл с именем signin.html . Откройте signin.html и добавьте следующий HTML-код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!DOCTYPE html>
<html lang=»en»>
  <head>
    <title>Python Flask Bucket List App</title>
 
    
    <link href=»http://getbootstrap.com/dist/css/bootstrap.min.css» rel=»stylesheet»>
 
    <link href=»http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css» rel=»stylesheet»>
    <link href=»../static/css/signup.css» rel=»stylesheet»>
    <script src=»../static/js/jquery-1.11.2.js»></script>
    
  </head>
 
  <body>
 
    <div class=»container»>
      <div class=»header»>
        <nav>
          <ul class=»nav nav-pills pull-right»>
            <li role=»presentation» ><a href=»/»>Home</a></li>
            <li role=»presentation» class=»active»><a href=»#»>Sign In</a></li>
            <li role=»presentation» ><a href=»/showSignUp»>Sign Up</a></li>
          </ul>
        </nav>
        <h3 class=»text-muted»>Python Flask App</h3>
      </div>
 
      <div class=»jumbotron»>
        <h1>Bucket List App</h1>
        <form class=»form-signin» action=»/validateLogin» method=»post»>
        <label for=»inputEmail» class=»sr-only»>Email address</label>
        <input type=»email» name=»inputEmail» id=»inputEmail» class=»form-control» placeholder=»Email address» required autofocus>
        <label for=»inputPassword» class=»sr-only»>Password</label>
        <input type=»password» name=»inputPassword» id=»inputPassword» class=»form-control» placeholder=»Password» required>
         
        <button id=»btnSignIn» class=»btn btn-lg btn-primary btn-block» type=»submit»>Sign in</button>
      </form>
      </div>
 
       
 
      <footer class=»footer»>
        <p>&copy;
      </footer>
 
    </div>
  </body>
</html>

Откройте app.py и добавьте новый маршрут для интерфейса входа.

1
2
3
@app.route(‘/showSignin’)
def showSignin():
    return render_template(‘signin.html’)

Затем откройте index.html и signup.html и добавьте ссылку href для входа на обе страницы как /showSignin . Сохраните все изменения и перезапустите сервер.

1
python app.py

В браузере укажите http: // localhost: 5002 и нажмите на ссылку « Войти» , и вы увидите страницу входа.

Страница входа

Теперь нам нужно создать функцию для проверки логина пользователя. При нажатии на кнопку « Войти» мы отправим введенный адрес электронной почты и пароль в функцию подтверждения пользователя.

Для проверки пользователя нам понадобится хранимая процедура MySQL. Поэтому создайте хранимую процедуру MySQL, как показано ниже:

1
2
3
4
5
6
7
8
DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_validateLogin`(
IN p_username VARCHAR(20)
)
BEGIN
    select * from tbl_user where user_username = p_username;
END$$
DELIMITER ;

Мы получим данные пользователя на основе имени username из базы данных MySQL, используя sp_validateLogin . Получив хешированный пароль, мы проверим его по паролю, введенному пользователем.

Создайте метод для проверки пользователя, который мы будем вызывать, когда пользователь отправляет форму:

1
2
3
4
5
6
7
8
@app.route(‘/validateLogin’,methods=[‘POST’])
def validateLogin():
    try:
        _username = request.form[‘inputEmail’]
        _password = request.form[‘inputPassword’]
 
    except Exception as e:
        return render_template(‘error.html’,error = str(e))

Как видно из приведенного выше кода, мы прочитали адрес электронной почты и пароль в _username и _password . Теперь мы sp_validateLogin процедуру sp_validateLogin с параметром _username . Поэтому создайте соединение MySQL внутри метода validateLogin :

1
con = mysql.connect()

Как только соединение будет создано, создайте cursor используя соединение con .

1
cursor = con.cursor()

Используя курсор, вызовите хранимую процедуру MySQL, как показано ниже:

1
cursor.callproc(‘sp_validateLogin’,(_username,))

Получить извлеченные записи из курсора, как показано:

1
data = cursor.fetchall()

Если данные содержат несколько записей, мы сопоставим полученный пароль с паролем, введенным пользователем.

1
2
3
4
5
6
7
if len(data) > 0:
    if check_password_hash(str(data[0][3]),_password):
        return redirect(‘/userHome’)
    else:
        return render_template(‘error.html’,error = ‘Wrong Email address or Password.’)
else:
    return render_template(‘error.html’,error = ‘Wrong Email address or Password.’)

Как видно из приведенного выше кода, мы использовали метод, называемый check_password_hash чтобы проверить, соответствует ли возвращенный хэш-пароль паролю, введенному пользователем. Если все хорошо, мы перенаправим пользователя в userHome.html . И если есть какая-либо ошибка, мы отобразим error.html с сообщением об ошибке.

Вот полный код validateLogin :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@app.route(‘/validateLogin’,methods=[‘POST’])
def validateLogin():
    try:
        _username = request.form[‘inputEmail’]
        _password = request.form[‘inputPassword’]
 
 
 
        # connect to mysql
 
        con = mysql.connect()
        cursor = con.cursor()
        cursor.callproc(‘sp_validateLogin’,(_username,))
        data = cursor.fetchall()
 
 
 
 
        if len(data) > 0:
            if check_password_hash(str(data[0][3]),_password):
                session[‘user’] = data[0][0]
                return redirect(‘/userHome’)
            else:
                return render_template(‘error.html’,error = ‘Wrong Email address or Password.’)
        else:
            return render_template(‘error.html’,error = ‘Wrong Email address or Password.’)
 
 
    except Exception as e:
        return render_template(‘error.html’,error = str(e))
    finally:
        cursor.close()
        con.close()

Создайте страницу с именем userHome.html внутри папки шаблонов и добавьте следующий HTML-код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html lang=»en»>
 
<head>
    <title>Python Flask Bucket List App</title>
 
 
    <link href=»http://getbootstrap.com/dist/css/bootstrap.min.css» rel=»stylesheet»>
 
    <link href=»http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css» rel=»stylesheet»>
    <link href=»../static/css/signup.css» rel=»stylesheet»>
 
 
</head>
 
<body>
 
    <div class=»container»>
        <div class=»header»>
            <nav>
                <ul class=»nav nav-pills pull-right»>
                    <li role=»presentation» class=»active»><a href=»/logout»>Logout</a>
                    </li>
                </ul>
            </nav>
            <h3 class=»text-muted»>Python Flask App</h3>
        </div>
 
        <div class=»jumbotron»>
            <h1>Welcome Home !!</h1>
 
        </div>
 
 
        <footer class=»footer»>
            <p>&copy;
        </footer>
 
    </div>
</body>
 
</html>

Также создайте страницу ошибки с именем error.html в папке templates и добавьте следующий HTML-код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html lang=»en»>
 
<head>
    <title>Unauthorized Access:: Python Flask Bucket List App</title>
 
 
    <link href=»http://getbootstrap.com/dist/css/bootstrap.min.css» rel=»stylesheet»>
 
    <link href=»http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css» rel=»stylesheet»>
 
 
</head>
 
<body>
 
    <div class=»container»>
        <div class=»header»>
            <nav>
                <ul class=»nav nav-pills pull-right»>
                    <li role=»presentation» class=»active»><a href=»#»>Home</a>
                    </li>
                    <li role=»presentation»><a href=»/showSignin»>Sign In</a>
                    </li>
                    <li role=»presentation»><a href=»/showSignUp»>Sign Up</a>
                    </li>
                </ul>
            </nav>
            <h3 class=»text-muted»>Python Flask App</h3>
        </div>
 
        <div class=»jumbotron»>
            <h1>{{error}}</h1>
        </div>
 
 
 
        <footer class=»footer»>
            <p>&copy;
        </footer>
 
    </div>
</body>
 
</html>

Внутри error.html у нас есть элемент, как показано:

1
<h1>{{error}}</h1>

Значение для переменной может быть передано из функции render_template и может быть установлено динамически.

При успешном входе мы перенаправляем пользователя на домашнюю страницу пользователя, поэтому нам нужно создать маршрут с именем /userHome как показано ниже:

1
2
3
@app.route(‘/userHome’)
def userHome():
    return render_template(‘userHome.html’)

Сохраните все изменения и перезапустите сервер. Нажмите на ссылку « Войти» на главной странице и попробуйте войти, используя действующий адрес электронной почты и пароль. При успешной проверке пользователя у вас должна быть страница, как показано ниже:

Дом пользователя при успешном входе пользователя

При неудачной проверке пользователя пользователь будет перенаправлен на страницу ошибки, как показано ниже:

Сообщение об ошибке при неудачном входе пользователя

Здесь мы использовали отдельную страницу ошибок для отображения ошибки. Также хорошо, если вы хотите использовать ту же страницу для отображения сообщения об ошибке.

При успешной проверке пользователя пользователь перенаправляется на домашнюю страницу пользователя. Но прямо сейчас даже неавторизованный пользователь может просматривать домашнюю страницу, просто просматривая URL-адрес http: // localhost: 5002 / userHome .

Чтобы ограничить неавторизованный доступ пользователей, мы проверим переменную сеанса, которую мы установим при успешном входе пользователя. Итак, импортируем session из колбы:

1
from flask import session

Нам также нужно установить секретный ключ для сессии. Поэтому в app.py после инициализации приложения установите секретный ключ, как показано ниже:

1
app.secret_key = ‘why would I tell you my secret key?’

Теперь внутри метода validateLogin перед перенаправлением пользователя в /userHome при успешном входе установите переменную session как показано ниже:

1
session[‘user’] = data[0][0]

Затем, внутри метода userHome , проверьте переменную сеанса перед рендерингом userHome.html . Если переменная сеанса не найдена, перенаправьте на страницу ошибки.

1
2
3
4
5
6
@app.route(‘/userHome’)
def userHome():
    if session.get(‘user’):
        return render_template(‘userHome.html’)
    else:
        return render_template(‘error.html’,error = ‘Unauthorized Access’)

Сохраните все изменения и перезапустите сервер. Не входя в систему, попробуйте перейти по адресу http: // localhost: 5002 / userHome, и, поскольку вы еще не вошли в систему, вы должны будете перенаправлены на страницу с ошибкой.

Ошибка несанкционированного доступа

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

Внутри app.py создайте новый маршрут и метод для logout как показано:

1
2
3
4
@app.route(‘/logout’)
def logout():
    session.pop(‘user’,None)
    return redirect(‘/’)

Мы уже установили href для кнопки /logout . Сохраните все изменения и перезапустите сервер. На домашней странице нажмите « Войти» и попробуйте войти, используя действующий адрес электронной почты и пароль. После входа нажмите кнопку « Выйти» в домашней странице пользователя, и вы должны успешно выйти из приложения.

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

Исходный код из этого урока доступен на GitHub .

Дайте нам знать ваши мысли в комментариях ниже!