您的位置:首页 > 运维架构

8.1 使用Werkzeug实现密码散列(ps: 末尾有介绍@property装饰器)

2018-03-11 15:48 281 查看
————————————————————————前言——————————————————————————
数据库中的密码是不安全的, 一旦恶意用户得到数据库的访问权, 那我们的密码就会被泄露, 利益必然受损。
所以我们不应该在数据库中直接存储密码, 而是要存储密码对应的散列值。
————————————————————————————————————————————————————

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

from werkzeug.security import generate_password_hash, check_password_hash

from . import db

class 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 unittest

from app.models import User

class 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.age

3   调用函数设置和获得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_hash

from . import db

class 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐