python连接数据库(pymysql)及数据库加密
内容:
1.pymysql介绍
2.pymysql基本使用
3.数据库加密
参考:http://www.cnblogs.com/wupeiqi/articles/5713330.html
1.pymysql介绍
pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同,在python3 中以及不支持MySQLdb这个模块了,所有我们现在只用学习pymysql即可
安装:
1 pip3 install pymysql
2.pymysql基本使用
(1)预备知识:SQL
sql详细:http://www.cnblogs.com/wyb666/p/9017402.html
1 数据库通过 SQL 来操作数据 2 SQL (结构化查询语言)-> 操作数据库的接口 也就是操作数据库的方法 3 增加数据 删除数据 修改数据 查询数据 4 CRUD 5 create retrieve update delete
(2)使用pymysql操作MySQL的大致流程
1 import pymysql 2 3 # 创建连接 4 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') 5 # 创建游标 6 cursor = conn.cursor() 7 8 # 执行SQL,并返回收影响行数 9 effect_row = cursor.execute("update hosts set host = '1.1.1.2'") 10 11 # 执行SQL,并返回受影响行数 12 #effect_row = cursor.execute("update hosts set host = '1.1.1.2' where nid > %s", (1,)) 13 14 # 执行SQL,并返回受影响行数 15 #effect_row = cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)]) 16 17 18 # 提交,不然无法保存新建或者修改的数据 19 conn.commit() 20 21 # 关闭游标 22 cursor.close() 23 # 关闭连接 24 conn.close()
(3)对以上过程的封装
看到这里你可能会好奇,以上那种用法不是蛮好吗,直接从上到下执行代码,干嘛还要封装,封装是为了代码的逻辑性更强,另外代码具有更多的可拓展性,我们自己封装直接封装成函数即可,不必封装成类(那样也可以不过太麻烦太复杂了),当然我们也可以使用别人的封装(后面要学到的SQLAlchemy就是一种简单的封装,其将对数据库的操作封装成对类的操作)
SQL操作无非可分为以下几种:
- 创建库表
- 增删改查数据
所以我将这些功能封装成相应的函数即可,如下所示:
1 # __author__ = "wyb" 2 # date: 2018/8/20 3 import pymysql 4 5 6 # 创建数据库中的表 7 def create(conn): 8 # 注意 CREATE TABLE 这种语句不分大小写 9 sql_create = ''' 10 CREATE TABLE `users` ( 11 `id` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, 12 `username` VARCHAR(200) NOT NULL UNIQUE, 13 `password` TEXT NOT NULL, 14 `email` TEXT 15 ) 16 ''' 17 # 用 execute 执行一条 sql 语句 18 conn.execute(sql_create) 19 print('创建成功') 20 21 22 # 向数据库中插入数据 23 def insert(conn, username, password, email): 24 sql_insert = ''' 25 INSERT INTO 26 users(username,password,email) 27 VALUES 28 (%s, %s, %s); 29 ''' 30 # 参数拼接要用 %s,execute 中的参数传递必须是一个 tuple 类型 31 conn.execute(sql_insert, (username, password, email, )) 32 print('插入数据成功') 33 34 35 # 查询数据 36 def select(conn): 37 sql = ''' 38 SELECT 39 * 40 FROM 41 users 42 ''' 43 # 这是读取数据的套路 44 conn.execute(sql) 45 res = conn.fetchall() 46 print("所有数据如下: ") 47 for row in res: 48 print(row) 49 50 51 # 删除数据 52 def delete(conn, user_id): 53 sql_delete = ''' 54 DELETE FROM 55 users 56 WHERE 57 id=%s 58 ''' 59 # 注意, execute 的第二个参数是一个 tuple 60 # tuple 只有一个元素的时候必须是这样的写法 61 conn.execute(sql_delete, (user_id,)) 62 print("删除数据成功") 63 64 65 # 更新数据 66 def update(conn, user_id, email): 67 sql_update = ''' 68 UPDATE 69 `users` 70 SET 71 `email` = %s 72 WHERE 73 `id`= %s 74 ''' 75 conn.execute(sql_update, (email, user_id)) 76 print("更新数据成功") 77 78 79 # 主程序 80 def main(): 81 # 指定数据库名字并打开 -> 没有会自动创建 82 # 创建连接 83 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root', db='wyb') 84 print("打开数据库wyb") 85 # 创建游标 86 cursor = conn.cursor() 87 88 # create 创建表结构 -> 注意创建表只能创建一次 创建已创建的表会报错 89 # create(cursor) 90 91 # insert 插入数据 -> 注意插入一次后下面的数据就不能再插入 因为用户名有限制(unique) 92 # insert(cursor, 'wpz', '123', 'tggh@b.c') 93 94 # delete 删除数据 95 # delete(cursor, 1) 96 97 # update 更新数据 98 # update(cursor, 4, 'woz_wyb@qq.com') 99 # select 查询数据 100 # select(cursor) 101 102 # 最后提交: 必须用 commit 函数提交你的修改 否则你的修改不会被写入数据库 103 conn.commit() 104 # 用完数据库要关闭 105 cursor.close() 106 conn.close() 107 108 109 if __name__ == '__main__': 110 main()
先运行上述代码中的create函数,然后操作如下:
可以明显看到现在已经通过程序建立了数据库的表结构,接下来使用其他函数体验一下增删改查(insert、delete、update、select),每个函数运行完后在终端上
使用select * from users;查看表中数据变化
(4)fetch数据类型
默认获取的数据是元祖类型,如果想要或者字典类型的数据,即:
1 import pymysql 2 3 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') 4 5 # 游标设置为字典类型 6 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) 7 r = cursor.execute("call p1()") 8 9 result = cursor.fetchone() 10 11 conn.commit() 12 cursor.close() 13 conn.close()
3.数据库加密
众所周知,数据库加密是十分重要的,因为数据库会存储一些敏感信息,比如密码,即使我们的程序没有任何的安全漏洞不会被黑客攻击,但是程序所在的服务器可能有安全漏洞,我们使用的数据库软件可能会有漏洞,因此要对数据中的一些敏感信息(比如密码)进行加密存储
(1)数据库加密方法
常见的加密算法有对称加密、非对称加密以及hash算法,一般数据库中敏感信息使用hash算法加密即可
常见的Hash算法:MD2、MD4、MD5、HAVAL、SHA、SHA-1、HMAC、HMAC-MD5、HMAC-SHA1
(2)加密实例
注册登录验证(密码加密):
1 class User(Model): 2 """ 3 User 是一个保存用户数据的 model 4 现在只有两个属性 username 和 password 5 """ 6 def __init__(self, form): 7 self.id = form.get('id', None) 8 self.username = form.get('username', '') 9 self.password = form.get('password', '') 10 11 # 加盐加密 12 @staticmethod 13 def salted_password(password, salt="`1234567890~!@#$%^&*()-=[];'\/,./ZXCVBNSADFYWQET"): 14 # salt: "`1234567890~!@#$%^&*()-=[];'\/,./ZXCVBNSADFYWQET" 15 def md5hex(ascii_str): 16 return hashlib.md5(ascii_str.encode('ascii')).hexdigest() 17 18 # 普通加密 19 hash1 = md5hex(password) 20 # 加盐加密 21 hash2 = md5hex(hash1 + salt) 22 return hash2 23 24 # 注册 25 def validate_register(self): 26 pwd = self.password 27 self.password = self.salted_password(pwd) 28 # 用户名已存在就不允许注册 否则可以注册 29 if User.find_by(username=self.username) is None: 30 self.save() 31 return self 32 else: 33 return None 34 35 # 登录 36 def validate_login(self): 37 u = User.find_by(username=self.username) 38 if u is not None: 39 return u.password == self.salted_password(self.password) 40 else: 41 return False 42 43 # 修改密码 44 def change_pwd(self, form): 45 # 输入两次旧密码不一样 46 pwd1 = form.get("pwd1", "") 47 pwd2 = form.get("pwd2", "") 48 if pwd1 != pwd2: 49 res = { 50 "msg": "两次输入的旧密码不一样", 51 "data": None, 52 } 53 return res 54 55 # 输入的旧密码正确就重置 否则就不重置 56 new_pwd = form.get("new_pwd", "") 57 if self.salted_password(pwd1) == self.password: 58 self.password = self.salted_password(new_pwd) 59 self.save() 60 res = { 61 "msg": "重置密码成功", 62 "data": self, 63 } 64 else: 65 res = { 66 "msg": "输入的旧密码错误!", 67 "data": None, 68 } 69 return res
注意:上述代码不是完整代码,但不用关心其他细节,只关心具体的加密以及验证方法
上述代码的加密逻辑:
使用python的hashlib加密模块,先用普通的md5的hash算法直接对密码进行加密,然后再对加密后的密文加上盐再进行加密
验证逻辑:
将用户输入的密码同样使用上述方法加密,如果最后结果和数据库中存的结果是一样的,那么就通过验证,否则验证失败
由此,可以得出结论:
假设密码存入数据库均经过上述过程中的hash加密,那么除了用户本人没有人会知道到底密码是什么(当然黑客破解也不是不行,但破解难度极大),所以当忘记密码时一般都不能直接找回密码,而是通过回答密保问题(或其他方式)来修改密码,因为除了用户自己没有人知道密码是什么