博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
8.1 使用Werkzeug实现密码散列(ps: 末尾有介绍@property装饰器)
阅读量:4095 次
发布时间:2019-05-25

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

————————————————————————前言——————————————————————————

数据库中的密码是不安全的, 一旦恶意用户得到数据库的访问权, 那我们的密码就会被泄露, 利益必然受损。

所以我们不应该在数据库中直接存储密码, 而是要存储密码对应的散列值。

————————————————————————————————————————————————————

一. 修改models.py脚本中的User类

from werkzeug.security import generate_password_hash, check_password_hashfrom . import dbclass User(db.Model):    #...    password_hash = db.Column(db.String(128))  #增加一个hash密码字段    @property    def password(self):           raise AttributeError('password is not a readable attribute')  #实例访问password属性时,会引发属性错误    @password.setter    def password(self, password):  #实例设置password属性时, 就会调用该函数生成密码hash值        self.password_hash = generate_password_hash(password)     def verify_password(self, password):  #验证密码是否符合之前存储的hash值        return check_password_hash(self.password_hash, password)

@property 和 @password.setter修饰器在文末会有介绍。

二. 增加一个测试脚本test_user_model.py

import unittestfrom app.models import Userclass userModelTestCase(unittest.TestCase):    def test_password_setter(self):  #测试hash值是否设置成功        u = User(password='cat')        self.assertTrue(u.password_hash is not None)    def test_no_password_getter(self):  #测试实例是否不能访问password属性        u = User(password='cat')        with self.asssertRaise(AttributeError):            u.password    def test_password_verification(self):  #测试密码验证函数        u = User(password='cat')        self.assertTrue(u.verify_password('cat'))        self.assertFalse(u.verify_password('dog'))    def test_password_salts_are_random(self):  #测试密码加盐是随机的: 不同用户的相同密码, hash值也不同        u = User(password='cat')        u2 = User(password='cat')        self.assertTrue(u.password_hash != u2.password_hash)

测试效果展示:

三. 修饰器property和password.setter

1. 我们先举一个简单的小例子

class Person(object): #Person类    def getAge(self):        return self._age    def setAge(self, age):        self._age = age>p = Person()  #创建Person实例>p.setAge(3)  #设置p.age为3>p.getAge()  #获得p.age3

   调用函数设置和获得age值不免显得麻烦, 如果能用p.age = 3设置属性值, p.age获得属性值就会显得简单易懂。

  我们可以用@property装饰器实现上述操作, 把getter方法变成属性, 并且@property本身又创建了另一个装饰器@password.setter, 把setter方法变成属性赋值:

class Person(object):    @property    def age(self):        return self._age    @age.setter    def age(self, age):        self._age = age>p = Person()  #创建实例>p.age = 3   #相当于调用p.age(3)>p.age  #相当于调用p.age()3

回到我们的User类:

from werkzeug import generate_password_hash, check_password_hashfrom . import dbclass User(db.Model):    #...    password_hash = db.Column(db.String(128))    @property    def password(self):        raise attributeError('password is not a readable attribute')    @password.setter    def password(self, password):        self.password_hash = generate_password_hash(password)User类中我们把password设置为只读属性, 试图访问该属性会引发错误>u = User()  #创建实例>u.password = 'cat'  #相当于调用u.password('cat'), 把u.password_hash赋值为generate_password_hash('cat')>u.password  #相当于调用u.password(), 引发attributeError
你可能感兴趣的文章
Set Matrix Zeroes
查看>>
Search a 2D Matrix
查看>>
Binary Tree Inorder Traversal
查看>>
error: cannot lock ref 'a/b/c/d' exists; cannot create 'a/b/c/d'
查看>>
双重哈希
查看>>
在Mac上安装consolas字体
查看>>
Rails db rake命令
查看>>
Git: This branch is out-of-date with the base branch
查看>>
Git: There is no tracking information for the current branch.
查看>>
https git clone与ssh git clone之间的区别
查看>>
在Spring中,Bean有几种作用域?
查看>>
[JAVA学习笔记-68]NIO与AIO的区别
查看>>
[JAVA学习笔记-70]AIO handler form
查看>>
[JAVA学习笔记-69]Reactor与Proactor模式
查看>>
[JAVA学习笔记-72]关于Priority Inversion
查看>>
[JAVA学习笔记-74]了解JDBC
查看>>
[JAVA学习笔记-75]关于CAS
查看>>
[JAVA学习笔记-76]volatile的原子性与可见性
查看>>
[JAVA学习笔记-77]关于BlockingQueue
查看>>
[JAVA学习笔记-78]lockInterruptibly
查看>>