本文共 2846 字,大约阅读时间需要 9 分钟。
————————————————————————前言——————————————————————————
数据库中的密码是不安全的, 一旦恶意用户得到数据库的访问权, 那我们的密码就会被泄露, 利益必然受损。
所以我们不应该在数据库中直接存储密码, 而是要存储密码对应的散列值。
————————————————————————————————————————————————————
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修饰器在文末会有介绍。
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)
测试效果展示:
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