用 Flask 来写个轻博客 (19) — 以 Bcrypt 密文存储账户信息与实现用户登陆表单
目录
前文列表
用 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 instance
bcrypt = Bcrypt()
NOTE 1:以后所有会使用到的 Flask 扩展都会在 extensions.py 中。
- jmilkfansblog/__init__.py
from flask import Flask, redirect, url_for
from jmilkfansblog.models import db
from jmilkfansblog.controllers import blog
from jmilkfansblog.extensions import bcrypt
def 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 bcrypt
class 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.password
u'$2b$12$omKgt8saJydyfbBYwMnms.1ihw7Ox6alBPKdYsPUKtzaBQaNM4Guy'
创建登陆表单
- forms.py
from flask_wtf import Form
from wtforms import (
StringField,
TextField,
TextAreaField,
PasswordField,
BooleanField,
ValidationError
)
from wtforms.validators import DataRequired, Length, EqualTo, URL
from jmilkfansblog.models import User
class 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
return True
- NOTE 1: LoginForm 重载的 validate() 中调用了父类 Form 中的 validate(),用于检验用户输入的数据是否通过了 username/password 字段的检验器。
- NOTE 2:LoginForm 重载的 validate() 不仅仅实现了父类的功能,还实现了检验 username 是否存在和用户输入的 password 是否正确的功能。子类重载父类的方法结合 super() 内置函数是 Python OOP 中常用的技巧。
用 Flask 来写个轻博客 (19) — 以 Bcrypt 密文存储账户信息与实现用户登陆表单的更多相关文章
- 用 Flask 来写个轻博客
用 Flask 来写个轻博客 用 Flask 来写个轻博客 (1) — 创建项目 用 Flask 来写个轻博客 (2) — Hello World! 用 Flask 来写个轻博客 (3) — (M)V ...
- 用 Flask 来写个轻博客 (37) — 在 Github 上为第一阶段的版本打 Tag
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 第一阶段结语 打 Tag 前文列表 用 Flask 来写个轻博客 (1 ...
- 用 Flask 来写个轻博客 (36) — 使用 Flask-RESTful 来构建 RESTful API 之五
目录 目录 前文列表 PUT 请求 DELETE 请求 测试 对一条已经存在的 posts 记录进行 update 操作 删除一条记录 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 ...
- 用 Flask 来写个轻博客 (35) — 使用 Flask-RESTful 来构建 RESTful API 之四
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 POST 请求 身份认证 测试 前文列表 用 Flask 来写个轻博客 ...
- 用 Flask 来写个轻博客 (34) — 使用 Flask-RESTful 来构建 RESTful API 之三
目录 目录 前文列表 应用请求中的参数实现 API 分页 测试 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask 来写个轻博客 (2) - Hello World! 用 F ...
- 用 Flask 来写个轻博客 (33) — 使用 Flask-RESTful 来构建 RESTful API 之二
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 构建 RESTful Flask API 定义资源路由 格式 ...
- 用 Flask 来写个轻博客 (32) — 使用 Flask-RESTful 来构建 RESTful API 之一
目录 目录 前文列表 扩展阅读 RESTful API REST 原则 无状态原则 面向资源 RESTful API 的优势 REST 约束 前文列表 用 Flask 来写个轻博客 (1) - 创建项 ...
- 用 Flask 来写个轻博客 (31) — 使用 Flask-Admin 实现 FileSystem 管理
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 编写 FileSystem Admin 页面 Flask-A ...
- 用 Flask 来写个轻博客 (30) — 使用 Flask-Admin 增强文章管理功能
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 实现文章管理功能 实现效果 前文列表 用 Flask 来写个 ...
随机推荐
- jmeter处理接口加密和解密
https://www.liangzl.com/get-article-detail-39672.html https://www.cnblogs.com/artoftest/p/7277996.ht ...
- sqlalchemy的不区分大小写比较
方法一:collation 参照:https://segmentfault.com/q/1010000010203547 方法是在 db.String 中添加 collation='NOCASE' 描 ...
- [Codeforces 639F] Bear and Chemistry (Tarjan+虚树)(有详细注释)
[Codeforces 639F] Bear and Chemistry(Tarjan+虚树) 题面 给出一个n个点,m条边的无向图(不保证连通,可能有自环和重边),有q次询问,每次询问给出p个点和q ...
- 在pythonanywhere部署你的第一个应用
pythonanywhere是一个免费的托管python的代码,可以测试你的web应用,用起来还是比较方便的,现在就来介绍如何在pythonanywhere部署你的应用. 下载你的代码 我的代码是托管 ...
- console.log的高级用法
//基本用法 console.log('最常见用法\n换行'); console.error('输出错误信息 会以红色显示'); console.warn('打印警告信息 会以黄色显示'); cons ...
- cookie和session的联系与区别
Cookie 当你在浏览网站时,WEB服务器会先送一小小的资料放在你的计算机上,Cookie会帮你在网站上所打的文字或是一些选择都记录下来.当你下次再光临同一个网站时,WEB服务器会先看看有没有它上次 ...
- PeStudio读取pe信息
https://blog.csdn.net/x_xx_xxx_xxxx/article/details/79867928 PeStudio 主要利用此界面工具 https://blog.csdn.n ...
- Python错误提示:[Errno 24] Too many open files的分析与解决
背景 最近在工作中发现了一个错误,在执行多线程扫描脚本的时候频繁出现下面这个错误 HTTPConnectionPool(host=‘t.tips', port=80): Max retries exc ...
- HTML5:新元素来实现一下网页布局
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- OpenCV图像数据字节对齐
目录 1. IplImage的data字段,是char*类型,是4字节对齐. 2. 手动创建的Mat通常是没有字节对齐的 3. 从IplImage转过来的Mat,是字节对齐的 4. 总结 图像数据是否 ...