8.1 使用Werkzeug实现密码散列(ps: 末尾有介绍@property装饰器)
2018-03-11 15:48
281 查看
————————————————————————前言——————————————————————————
数据库中的密码是不安全的, 一旦恶意用户得到数据库的访问权, 那我们的密码就会被泄露, 利益必然受损。
所以我们不应该在数据库中直接存储密码, 而是要存储密码对应的散列值。
————————————————————————————————————————————————————
测试效果展示:
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
数据库中的密码是不安全的, 一旦恶意用户得到数据库的访问权, 那我们的密码就会被泄露, 利益必然受损。
所以我们不应该在数据库中直接存储密码, 而是要存储密码对应的散列值。
————————————————————————————————————————————————————
一. 修改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
相关文章推荐
- 使用Werkzeug实现密码散列
- Flask学习记录之使用Werkzeug散列密码
- JavaScript中如何使用cookie实现记住密码功能及cookie相关函数介绍
- 关于Apache mod_rewrite的中文配置、使用和语法介绍(实现URL重写和防盗链功能)
- [EntLib]微软企业库5.0 学习之路——第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——上篇
- 微软企业库5.0 学习之路——第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——上篇
- 使用ssh公钥实现ssh免密码登录
- Gnutella协议的相关介绍(Peercast实现P2P传输所使用的协议)
- 使用expect实现ssh自动输入密码,从而自动登陆Linux
- 使用expect 实现 scp 文件的时候不手动输入密码
- 一种hashtable 实现的使用介绍
- 使用SVN+CruiseControl+ANT实现持续集成之一----持续集成概念及CC原理介绍
- 使用SVN+CruiseControl+ANT实现持续集成之一----持续集成概念及CC原理介绍
- 使用SVN+CruiseControl+ANT实现持续集成之二----环境搭建和配置介绍
- 微软企业库5.0 学习之路——第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——中篇
- WINDOWS NT/2000 密码到散列的实现算法
- 使用SharpZipLib.dll动态库实现带密码压缩
- 使用profile的PASSWORD_VERIFY_FUNCTION参数实现自定义的密码验证规则
- 关于Apache mod_rewrite的中文配置、使用和语法介绍(实现URL重写和防盗链功能)
- 使用MD5加密数据库中的用户密码介绍