博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用 Flask 来写个轻博客 (19) — 以 Bcrypt 密文存储账户信息与实现用户登陆表单
阅读量:6540 次
发布时间:2019-06-24

本文共 4423 字,大约阅读时间需要 14 分钟。

Blog 项目源码:

目录

前文列表

修改 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 "
".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        return True
  • NOTE 1: LoginForm 重载的 validate() 中调用了父类 Form 中的 validate(),用于检验用户输入的数据是否通过了 username/password 字段的检验器。
  • NOTE 2:LoginForm 重载的 validate() 不仅仅实现了父类的功能,还实现了检验 username 是否存在和用户输入的 password 是否正确的功能。子类重载父类的方法结合 super() 内置函数是 Python OOP 中常用的技巧

转载于:https://www.cnblogs.com/jmilkfan-fanguiju/p/10589860.html

你可能感兴趣的文章
有关sqlite与sql
查看>>
MapXtreme 2005 学习心得 概述(一)
查看>>
php进一法取整、四舍五入取整、忽略小数等的取整数方法大全
查看>>
Hibernate的拦截器和监听器
查看>>
游戏中学习Bash技能
查看>>
ubuntu 12.04系统托盘不显示ibus输入法图标的解决方法
查看>>
WSDP
查看>>
Memory Management
查看>>
The Packaging Process in Yocto/OE
查看>>
JQUERY 对 表格中的数据重排序
查看>>
程序员常用借口指南
查看>>
关于PXE网络安装linux系统中碰到的个别问题
查看>>
awk 常用方法
查看>>
Android网络框架实现之【Retrofit+RxJava】
查看>>
Android文件的加密与解密
查看>>
SOAP webserivce 和 RESTful webservice 对比及区别
查看>>
【原】记录一句话
查看>>
Android标题栏,状态栏
查看>>
三数中值快速排序(长度小于3的数组转插入排序)
查看>>
Windows下安装Memcached for PHP
查看>>