用 Flask 来写个轻博客 (19) — 以 Bcrypt 密文存储账户信息与实现用户登陆表单
来源:互联网 发布:中经网数据库 编辑:程序博客网 时间:2024/05/22 05:45
目录
- 目录
- 前文列表
- 修改 User Model
- Flask Bcrypt
- 将 Bcrypt 应用到 User Model 中
- 创建登陆表单
前文列表
用 Flask 来写个轻博客 (1) — 创建项目
用 Flask 来写个轻博客 (2) — Hello World!
用 Flask 来写个轻博客 (3) — (M)VC_连接 MySQL 和 SQLAlchemy
用 Flask 来写个轻博客 (4) — (M)VC_创建数据模型和表
用 Flask 来写个轻博客 (5) — (M)VC_SQLAlchemy 的 CRUD 详解
用 Flask 来写个轻博客 (6) — (M)VC_models 的关系(one to many)
用 Flask 来写个轻博客 (7) — (M)VC_models 的关系(many to many)
用 Flask 来写个轻博客 (8) — (M)VC_Alembic 管理数据库结构的升级和降级
用 Flask 来写个轻博客 (9) — M(V)C_Jinja 语法基础快速概览
用 Flask 来写个轻博客 (10) — M(V)C_Jinja 常用过滤器与 Flask 特殊变量及方法
用 Flask 来写个轻博客 (11) — M(V)C_创建视图函数
用 Flask 来写个轻博客 (12) — M(V)C_编写和继承 Jinja 模板
用 Flask 来写个轻博客 (13) — M(V)C_WTForms 服务端表单检验
用 Flask 来写个轻博客 (14) — M(V)C_实现项目首页的模板
用 Flask 来写个轻博客 (15) — M(V)C_实现博文页面评论表单
用 Flask 来写个轻博客 (16) — MV(C)_Flask Blueprint 蓝图
用 Flask 来写个轻博客 (17) — MV(C)_应用蓝图来重构项目
用 Flask 来写个轻博客 (18) — 使用工厂模式来生成应用对象
修改 User Model
使用明文的方式存储账户数据是一个非常严重的安全隐患,要保护用户的密码,就要使用 哈希算法的单向加密方法。
哈希算法:对于相同的数据,哈希算法总是会生成相同的结果。
单向加密:就是信息在加密之后,其原始信息是不可能通过密文反向计算出来的。
所以,为了账户信息的安全,在数据库中存储的密码应该是被哈希过的哈希值。但是需要注意,哈希算法的种类很多,其中大多是是不安全的,可以被黑客 暴力破解。
暴力破解:通过遍历各种数据的哈希值,来找到匹配的哈希值,从而获取你的密码权限。
所以这里我们使用 Bcrypt 哈希算法,这是一种被刻意设计成抵消且缓慢的哈希计算方式,从而极大的加长了暴力破解的时间和成本,以此来保证安全性。
Flask Bcrypt
- 安装
(env) [root@flask-dev JmilkFan-s-Blog]# pip install Flask-Bcrypt(env) [root@flask-dev JmilkFan-s-Blog]# pip freeze > requirements.txt
NOTE: Flask Bcrypt 与 Flask SQLAlchemy 一样需要使用 app 对象来进行初始化,我们在 jmilkfansblog 目录下新建一个 extensions.py 来实现我们以后会使用到的所有 Flask 扩展。
将 Bcrypt 应用到 User Model 中
- extensions.py
from flask.ext.bcrypt import Bcrypt# Create the Flask-Bcrypt's instancebcrypt = Bcrypt()
NOTE 1:以后所有会使用到的 Flask 扩展都会在 extensions.py 中。
- jmilkfansblog/__init__.py
from flask import Flask, redirect, url_forfrom jmilkfansblog.models import dbfrom jmilkfansblog.controllers import blogfrom jmilkfansblog.extensions import bcryptdef create_app(object_name): """Create the app instance via `Factory Method`""" app = Flask(__name__) # Set the config for app instance app.config.from_object(object_name) # Will be load the SQLALCHEMY_DATABASE_URL from config.py to db object db.init_app(app) # Init the Flask-Bcrypt via app object bcrypt.init_app(app) @app.route('/') def index(): # Redirect the Request_url '/' to '/blog/' return redirect(url_for('blog.home')) # Register the Blueprint into app object app.register_blueprint(blog.blog_blueprint) return app
NOTE 2:模块中的导入路径最好使用绝对路径。
models.py
from jmilkfansblog.extensions import bcryptclass User(db.Model): """Represents Proected users.""" # Set the name for table __tablename__ = 'users' id = db.Column(db.String(45), primary_key=True) username = db.Column(db.String(255)) password = db.Column(db.String(255)) # one to many: User ==> Post # Establish contact with Post's ForeignKey: user_id posts = db.relationship( 'Post', backref='users', lazy='dynamic') def __init__(self, id, username, password): self.id = id self.username = username self.password = self.set_password(password) def __repr__(self): """Define the string format for instance of User.""" return "<Model User `{}`>".format(self.username) def set_password(self, password): """Convert the password to cryptograph via flask-bcrypt""" return bcrypt.generate_password_hash(password) def check_password(self, password): return bcrypt.check_password_hash(self.password, password)
set_password(self, password)
:在设定密码的时候,将明文密码转换成为 Bcrypt 类型的哈希值。check_password(self, password)
:检验输入的密码的哈希值,与存储在数据库中的哈希值是否一致。- 验证
>>> from uuid import uuid4>>> user = User(id=str(uuid4()), username='test_1', password='fanguiju')>>> db.session.add(user)>>> db.session.commit()>>> >>> >>> user = User.query.filter_by(username='test_1').first()>>> user.passwordu'$2b$12$omKgt8saJydyfbBYwMnms.1ihw7Ox6alBPKdYsPUKtzaBQaNM4Guy'
创建登陆表单
- forms.py
from flask_wtf import Formfrom wtforms import ( StringField, TextField, TextAreaField, PasswordField, BooleanField, ValidationError)from wtforms.validators import DataRequired, Length, EqualTo, URLfrom jmilkfansblog.models import Userclass LoginForm(Form): """Login Form""" username = StringField('Username', [DataRequired(), Length(max=255)]) password = PasswordField('Password', [DataRequired()]) def validate(self): """Validator for check the account information.""" check_validata = super(LoginForm, self).validate() # If validator no pass if not check_validata: return False # Check the user whether exist. user = User.query.filter_by(username=self.username.data).first() if not user: self.username.errors.append('Invalid username or password.') return False # Check the password whether right. if not user.check_password(self.password.data): self.username.errors.append('Invalid username or password.') return False
- NOTE 1: LoginForm 重载的 validate() 中调用了父类 Form 中的 validate(),用于检验用户输入的数据是否通过了 username/password 字段的检验器。
- NOTE 2:LoginForm 重载的 validate() 不仅仅实现了父类的功能,还实现了检验 username 是否存在和用户输入的 password 是否正确的功能。子类重载父类的方法结合 super() 内置函数是 Python OOP 中常用的技巧。
- 用 Flask 来写个轻博客 (19) — 以 Bcrypt 密文存储账户信息与实现用户登陆表单
- 用 Flask 来写个轻博客 (20) — 实现注册表单与应用 reCAPTCHA 来实现验证码
- 用 Flask 来写个轻博客 (21) — 结合 reCAPTCHA 验证码实现用户注册与登录
- 用 Flask 来写个轻博客 (15) — M(V)C_实现博文页面评论表单
- 用 Flask 来写个轻博客 (25) — 使用 Flask-Principal 实现角色权限功能
- 用 Flask 来写个轻博客 (26) — 使用 Flask-Celery-Helper 实现异步任务
- 用 Flask 来写个轻博客 (27) — 使用 Flask-Cache 实现网页缓存加速
- 用 Flask 来写个轻博客 (29) — 使用 Flask-Admin 实现后台管理 SQLAlchemy
- 用 Flask 来写个轻博客 (31) — 使用 Flask-Admin 实现 FileSystem 管理
- oracle登陆账户信息
- 用 Flask 来写个轻博客 (13) — M(V)C_WTForms 服务端表单检验
- 用flask开发个人博客(33)—— 使用itsdangerous进行账户的确认
- 用 Flask 来写个轻博客 (22) — 实现博客文章的添加和编辑页面
- 用 Flask 来写个轻博客 (10) — M(V)C_Jinja 常用过滤器与 Flask 特殊变量及方法
- 用flask开发个人博客(22)—— 使用Flask-Migrate实现数据库的更新
- 安装flask-bcrypt报错
- (C#)与Windows用户账户信息的获取
- 用 Flask 来写个轻博客 (14) — M(V)C_实现项目首页的模板
- Java中通过反射获取泛型实例
- WebStorm创建nodejs Express工程(node js web 开发),并进行git版本管理
- 基于OVS+VXLAN实现Docker容器跨主机通讯
- 模拟实现memmove函数
- VC单文档菜单栏如何固定
- 用 Flask 来写个轻博客 (19) — 以 Bcrypt 密文存储账户信息与实现用户登陆表单
- hibernate中多对一映射更新
- shell中date的一些用法
- C#创建COM组件,QT调用COM组件简单测试(VS2008+QT4.6.4)
- jsp自定义标签的问题Unable to load tag handler class
- MySQL5.7MHA+MaxScale2.0构建高可用环境
- [Lintcode]Minimum Size Subarray Sum 和大于S的最小子数组
- elasticsearch基础及java编程
- 【jzoj4908】【NOIP2016提高组】【愤怒的小鸟】【状态压缩动态规划】