這幾天學了MySQLdb的操作,覺得意猶未盡,python也已經學了有段時間,所以考慮着通過與數據庫的集成,寫一個簡單的登陸、注冊和更改密碼的系統。
最終代碼是寫了一百二十多行,基本的功能已經實現,就是界面不太友好,下一步是打算學一些GUI的庫,完善界面。
寫這個系統的初衷,源於在廖雪峰老師的網站上http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0013868328251266d86585fc9514536a638f06b41908d44000
接觸到的hashlib內建庫,覺得非常有意思,在接下來的記錄里,大家可以看到是如何被使用的
import MySQLdb import hashlib |
這個比較簡單,第一個庫是操縱MySQL數據庫的,第二個庫里有哈希算法(哈希算法將任意長度的二進制值映射為較短的固定長度的二進制值,這個小的二進制值稱為哈希值。)
兩者編寫的原則都是"高內聚,低耦合",這些我也是剛體會到,理解的也不深
建立這個函數的思路就是,將用戶輸入的username和password插入到數據庫里,這里尤為需要注意的是,存儲的密碼是經過特殊處理的,說白了其實就是哈希值,這樣就保證了即使有人在后台可以看到數據庫或者說被黑客惡意攻擊,用戶的密碼也是安全的。
def Register(username, password): # 調用hashlib里的方法,生成哈希值 md5 = hashlib.md5() # 這個屬於'加鹽',就是讓哈希值更復雜,不易破解 # 廖老師的那篇文章里講的很詳細 md5.update(password + 'wpy' + username) md = md5.hexdigest() # 生成哈希值 realpassword = md
# insert進數據庫 sql = "INSERT INTO LOGIN(USERNAME, PASSWORD) VALUES('%s', '%s')" % (username, realpassword) try: cursor.execute(sql) # 必須commit,否則數據庫不會更新 db.commit() except: db.rollback() |
要注意的是,存儲在數據庫里的password其實經過特殊處理的,所以在驗證的時候,也要先將用戶輸入的password用相同的方法轉換成哈希值,然后再比較
def Login(username, password): # 與Register()里生成哈希值的方法一樣 md5 = hashlib.md5() md5.update(password + 'wpy' + username) md = md5.hexdigest() realpassword = md
sql = "SELECT PASSWORD FROM LOGIN WHERE USERNAME = '%s'" % (username) cursor.execute(sql) # username是主鍵,至多有一條紀錄 pwd = cursor.fetchone()[0] # 返回布爾值 if pwd == realpassword: return True else: return False |
def Update(username, password):
md5 = hashlib.md5() md5.update(password + 'wpy' + username) md = md5.hexdigest() realpassword = md
sql = "UPDATE LOGIN SET PASSWORD = '%s' WHERE USERNAME = '%s'" %(realpassword, username) try: cursor.execute(sql) db.commit() except: db.rollback() |
- 在Register的時候,要驗證輸入的username是否已經存在,已經存在的話要允許用戶重新輸入,簡單的說要有一個循環來控制
- 在Login的時候,一要先檢查username是否存在(這個不是必要的,即也可以不驗證),二是如果用戶密碼輸入錯誤的話可以再次輸入,但次數要限制,不能超過五次
- 在Update的時候,用戶要首先驗證自己的身份,就是說要先輸入原先的username和password,正確的話才能執行Update
看代碼
初始化 //數據庫連接,新建Table
db = MySQLdb.connect("localhost", "(username)", "(password)", "testdb") cursor = db.cursor() cursor.execute("CREATE TABLE LOGIN(USERNAME VARCHAR(20) PRIMARY KEY, PASSWORD VARCHAR(40))") |
循環主體 //比較復雜,大部分時間都花在這里
# 最外面的一層循環,控制系統的結束 while True: # 根據用戶的輸入,決定系統是否終止 start = raw_input("You want to (R)egister or (L)ogin or (U)pdate?") # 判斷 if start.lower() == 'r':
while True: #用戶可以輸入多次username username = raw_input("Please input your new name:") sql = "SELECT PASSWORD FROM LOGIN WHERE USERNAME = '%s'" % username # 查詢不到結果返回None m = cursor.execute(sql) if m: print "'%s' has already existed.Please change your name." % username # 輸入錯誤的話重新循環 continue else: password = raw_input("Please input your password:") Register(username, password) print "Register sucessfully!" # while循環中斷的唯一途徑 break
elif start.lower() == 'l':
while True: # 頂層循環,控制用戶名的輸入 username = raw_input("Please input your name:") sql = "SELECT PASSWORD FROM LOGIN WHERE USERNAME = '%s'" % username m = cursor.execute(sql) if not m: print "'%s' doesn't exist.Please change your name." % username continue else: # 第二層循環,控制密碼輸入的次數 for i in range(5): password = raw_input("Please input your password:") if Login(username, password): print "Login sucessfully!" # 密碼正確,及時跳出循環 break else: print "The password is wrong.Please input again." # 循環正常結束的話,執行該else語句 else: print "You have tried 5 times. The system is locked." # 跳出頂層循環 break
elif start.lower() == 'u':
while True: username = raw_input("Please input your name:") sql = "SELECT PASSWORD FROM LOGIN WHERE USERNAME = '%s'" % username m = cursor.execute(sql) if not m: print "'%s' doesn't exist.Please change your name." % username continue else: for i in range(5): # 先輸入原始密碼 oldpassword = raw_input("Please input your old password:") # 原始密碼正確的話輸入新密碼 if Login(username, oldpassword): password = raw_input("Please input your new password:") Update(username, password) print "Update sucessfully!" # 及時跳出循環 break else: print "The password is wrong.Please input again." else: print "You have tried 5 times. The system is locked."
break # 大循環終止條件 else: break
print "The system is closed!" cursor.close() db.close() |
結束!!!!!!!!
結果如下
總結:這個系統,實現起來並不算難,代碼量也不多,一百多行,算是一次有益的嘗試,以前沒有做過,感覺還挺有意思的。邏輯思路並不復雜,但是要理清楚,先把系統的結構大體構件,再去填充,一邊寫一邊想的話,效率太低。真正的總結的話,其實是:一定要學GUI!!!!