內容:
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加密,那么除了用戶本人沒有人會知道到底密碼是什么(當然黑客破解也不是不行,但破解難度極大),所以當忘記密碼時一般都不能直接找回密碼,而是通過回答密保問題(或其他方式)來修改密碼,因為除了用戶自己沒有人知道密碼是什么