{% raw %}

Flask 和登录验证

原文: https://pythonspot.com/login-authentication-with-flask/

52.md - 图1

Flask 图标

在本教程中,您将学习如何使用 Flask 和 Python 构建登录 Web 应用程序。

建立一个 Flask 登录页面

创建此 Python 文件并将其另存为app.py

  1. from flask import Flask
  2. from flask import Flask, flash, redirect, render_template, request, session, abort
  3. import os
  4. app = Flask(__name__)
  5. @app.route('/')
  6. def home():
  7. if not session.get('logged_in'):
  8. return render_template('login.html')
  9. else:
  10. return "Hello Boss!"
  11. @app.route('/login', methods=['POST'])
  12. def do_admin_login():
  13. if request.form['password'] == 'password' and request.form['username'] == 'admin':
  14. session['logged_in'] = True
  15. else:
  16. flash('wrong password!')
  17. return home()
  18. if __name__ == "__main__":
  19. app.secret_key = os.urandom(12)
  20. app.run(debug=True,host='0.0.0.0', port=4000)

在此处创建了两条路由(您可以在浏览器 URL 栏中看到的路径):

  1. @app.route('/')
  2. @app.route('/login', methods=['POST'])

第一个显示基于登录条件的登录屏幕或主屏幕。第二个路由在登录时验证登录变量。

我们创建目录/templates/。 使用以下代码创建文件/templates/login.html

  1. {% block body %};
  2. {% if session['logged_in'] %};
  3. You're logged in already!
  4. {% else %};
  5. <form action="/login" method="POST">
  6. <input type="username" name="username" placeholder="Username">
  7. <input type="password" name="password" placeholder="Password">
  8. <input type="submit" value="Log in">
  9. </form>
  10. {% endif %};
  11. {% endblock %};
  12. {% endraw %};

使用以下命令运行 Web 应用程序:

  1. $ python hello.py

在您的网络浏览器中打开 http://localhost:5000/ ,然后会出现登录屏幕。 登录凭据显示在do_admin_login()函数中。

52.md - 图2

Pythonspot.com 登录界面

使它看起来很棒

功能正常时,登录屏幕看起来像 90 年代初期的用户界面(UI)。 我们从 codepen.io 中选择了一个随机登录模板。 我们使用文件style.css创建目录/static/

  1. * {
  2. box-sizing: border-box;
  3. }
  4. *:focus {
  5. outline: none;
  6. }
  7. body {
  8. font-family: Arial;
  9. background-color: #3498DB;
  10. padding: 50px;
  11. }
  12. .login {
  13. margin: 20px auto;
  14. width: 300px;
  15. }
  16. .login-screen {
  17. background-color: #FFF;
  18. padding: 20px;
  19. border-radius: 5px
  20. }
  21. .app-title {
  22. text-align: center;
  23. color: #777;
  24. }
  25. .login-form {
  26. text-align: center;
  27. }
  28. .control-group {
  29. margin-bottom: 10px;
  30. }
  31. input {
  32. text-align: center;
  33. background-color: #ECF0F1;
  34. border: 2px solid transparent;
  35. border-radius: 3px;
  36. font-size: 16px;
  37. font-weight: 200;
  38. padding: 10px 0;
  39. width: 250px;
  40. transition: border .5s;
  41. }
  42. input:focus {
  43. border: 2px solid #3498DB;
  44. box-shadow: none;
  45. }
  46. .btn {
  47. border: 2px solid transparent;
  48. background: #3498DB;
  49. color: #ffffff;
  50. font-size: 16px;
  51. line-height: 25px;
  52. padding: 10px 0;
  53. text-decoration: none;
  54. text-shadow: none;
  55. border-radius: 3px;
  56. box-shadow: none;
  57. transition: 0.25s;
  58. display: block;
  59. width: 250px;
  60. margin: 0 auto;
  61. }
  62. .btn:hover {
  63. background-color: #2980B9;
  64. }
  65. .login-link {
  66. font-size: 12px;
  67. color: #444;
  68. display: block;
  69. margin-top: 12px;
  70. }

login.html模板修改为:

  1. <link rel="stylesheet" href="/static/style.css" type="text/css">
  2. {% block body %};
  3. <form action="/login" method="POST">
  4. <div class="login">
  5. <div class="login-screen">
  6. <div class="app-title">
  7. <h1>Login</h1>
  8. </div>
  9. <div class="login-form">
  10. <div class="control-group">
  11. <input type="text" class="login-field" value="" placeholder="username" name="username">
  12. <label class="login-field-icon fui-user" for="login-name"></label></div>
  13. <div class="control-group">
  14. <input type="password" class="login-field" value="" placeholder="password" name="password">
  15. <label class="login-field-icon fui-lock" for="login-pass"></label></div>
  16. <input type="submit" value="Log in" class="btn btn-primary btn-large btn-block">
  17. </div>
  18. </div>
  19. </div>
  20. </form>
  21. {% endblock %};

重新启动应用程序后,将出现以下屏幕:

52.md - 图3

Python Flask 登录界面

很棒,不是吗? :-)

那么注销呢?

如您所见,没有注销按钮或功能。 创建起来非常容易。 下面提出的解决方案只是众多解决方案之一。 我们创建一个新的路由/logout,它直接指向函数logout()。 此函数清除会话变量并返回登录屏幕。

  1. @app.route("/logout")
  2. def logout():
  3. session['logged_in'] = False
  4. return home()

完整代码:

  1. from flask import Flask
  2. from flask import Flask, flash, redirect, render_template, request, session, abort
  3. import os
  4. app = Flask(__name__)
  5. @app.route('/')
  6. def home():
  7. if not session.get('logged_in'):
  8. return render_template('login.html')
  9. else:
  10. return "Hello Boss! <a href="/logout">Logout</a>"
  11. @app.route('/login', methods=['POST'])
  12. def do_admin_login():
  13. if request.form['password'] == 'password' and request.form['username'] == 'admin':
  14. session['logged_in'] = True
  15. else:
  16. flash('wrong password!')
  17. return home()
  18. @app.route("/logout")
  19. def logout():
  20. session['logged_in'] = False
  21. return home()
  22. if __name__ == "__main__":
  23. app.secret_key = os.urandom(12)
  24. app.run(debug=True,host='0.0.0.0', port=4000)

连接数据库

如果要使用多用户登录系统,则应在应用程序中添加一个数据库层。Flask 没有现成的数据库支持。 如果要数据库支持,则必须使用第三方库。 在本教程中,我们将使用 SqlAlchemy。 如果您没有安装,请执行以下操作:

  1. $ sudo pip install Flask-SqlAlchemy

SQLAlchemy 是用于 Python 编程语言的 SQL 工具箱和对象关系映射器(ORM)。 它支持 MySQL,Microsoft SQL Server 和许多其他关系数据库管理系统。 如果您不熟悉所有这些术语,请继续阅读。

创建文件tabledef.py

  1. from sqlalchemy import *
  2. from sqlalchemy import create_engine, ForeignKey
  3. from sqlalchemy import Column, Date, Integer, String
  4. from sqlalchemy.ext.declarative import declarative_base
  5. from sqlalchemy.orm import relationship, backref
  6. engine = create_engine('sqlite:///tutorial.db', echo=True)
  7. Base = declarative_base()
  8. ########################################################################
  9. class User(Base):
  10. """"""
  11. __tablename__ = "users"
  12. id = Column(Integer, primary_key=True)
  13. username = Column(String)
  14. password = Column(String)
  15. #----------------------------------------------------------------------
  16. def __init__(self, username, password):
  17. """"""
  18. self.username = username
  19. self.password = password
  20. # create tables
  21. Base.metadata.create_all(engine)

使用以下命令执行:

  1. python tabledef.py

该文件将创建数据库结构。在目录内,您将找到一个名为tutorial.db的文件。创建一个名为dummy.py的文件,其中将包含以下代码:

  1. import datetime
  2. from sqlalchemy import create_engine
  3. from sqlalchemy.orm import sessionmaker
  4. from tabledef import *
  5. engine = create_engine('sqlite:///tutorial.db', echo=True)
  6. # create a Session
  7. Session = sessionmaker(bind=engine)
  8. session = Session()
  9. user = User("admin","password")
  10. session.add(user)
  11. user = User("python","python")
  12. session.add(user)
  13. user = User("jumpiness","python")
  14. session.add(user)
  15. # commit the record the database
  16. session.commit()
  17. session.commit()

执行:

  1. $ python dummy.py

这会将伪数据放入数据库中。 最后,我们更新app.py

使用 SqlAlchemy 验证登录凭据

下一步是编写验证数据库中存在的用户和密码的功能。 使用 SqlAlchemy 我们可以做到这一点(虚拟/伪代码):

  1. @app.route('/test')
  2. def test():
  3. POST_USERNAME = "python"
  4. POST_PASSWORD = "python"
  5. Session = sessionmaker(bind=engine)
  6. s = Session()
  7. query = s.query(User).filter(User.username.in_([POST_USERNAME]), User.password.in_([POST_PASSWORD]) )
  8. result = query.first()
  9. if result:
  10. return "Object found"
  11. else:
  12. return "Object not found " + POST_USERNAME + " " + POST_PASSWORD

我们使用 SqlAlchemys Oject 关系映射(ORM)。 我们将对象映射到关系数据库表,反之亦然。 定义(用户)在tabledef.py中给出。s.query函数是构建查询的地方。 我们有两个条件:用户名和密码必须匹配。 如果对象存在,query.first()返回true,否则返回false。 这给出了以下总代码:

  1. from flask import Flask
  2. from flask import Flask, flash, redirect, render_template, request, session, abort
  3. import os
  4. from sqlalchemy.orm import sessionmaker
  5. from tabledef import *
  6. engine = create_engine('sqlite:///tutorial.db', echo=True)
  7. app = Flask(__name__)
  8. @app.route('/')
  9. def home():
  10. if not session.get('logged_in'):
  11. return render_template('login.html')
  12. else:
  13. return "Hello Boss! <a href="/logout">Logout</a>"
  14. @app.route('/login', methods=['POST'])
  15. def do_admin_login():
  16. POST_USERNAME = str(request.form['username'])
  17. POST_PASSWORD = str(request.form['password'])
  18. Session = sessionmaker(bind=engine)
  19. s = Session()
  20. query = s.query(User).filter(User.username.in_([POST_USERNAME]), User.password.in_([POST_PASSWORD]) )
  21. result = query.first()
  22. if result:
  23. session['logged_in'] = True
  24. else:
  25. flash('wrong password!')
  26. return home()
  27. @app.route("/logout")
  28. def logout():
  29. session['logged_in'] = False
  30. return home()
  31. if __name__ == "__main__":
  32. app.secret_key = os.urandom(12)
  33. app.run(debug=True,host='0.0.0.0', port=4000)

现在,您可以使用数据库表中定义的任何用户登录。

那么安全性呢?

我们在上面演示了一个简单的登录应用程序。 但是,正确保护它是您的工作。 有很多人会尝试闯入您的应用程序。

下载 Flask 示例

最佳做法:

  • 散列数据库密码。 不要将它们存储为纯文本格式。

  • 使用 HTTPS 来保护连接。

  • 记录失败的登录尝试。

  • 使用验证码可以防止暴力破解登录。

  • 其他? 在评论中写下它们。