使用Flask開發(fā)簡單接口(5)--數(shù)據(jù)加密處理

前言

在之前開發(fā)的接口中隙咸,我們設(shè)計把用戶信息存儲到數(shù)據(jù)庫時,沒有對數(shù)據(jù)進(jìn)行加密處理成洗,為了提高下安全性五督,我們今天就學(xué)習(xí)下,如何對用戶數(shù)據(jù)進(jìn)行加密加鹽處理瓶殃。

MD5加密加鹽

  • MD5加密

MD5是常用的一種加密方法充包,它具有不可逆性,也就是說它只能加密遥椿,而不能進(jìn)行解密基矮,相對較安全。如果需要在Python3中使用MD5加密修壕,直接使用內(nèi)建模塊 hashlib 就行了愈捅,無需額外安裝。

我們之前設(shè)置的 password 密碼是明文的慈鸠,比如 123456蓝谨,這個是沒有進(jìn)行加密的灌具,如果使用MD5加密后是這樣的:

import hashlib

def get_md5(str):
    """MD5加密處理"""
    md5 = hashlib.md5()  # 創(chuàng)建md5對象
    md5.update(str.encode("utf-8"))  # Python3中需要先轉(zhuǎn)換為 bytes 類型,才能加密
    return md5.hexdigest() # 返回密文

password = "123456"
print("MD5加密前:{}".format(password)) # 123456
md5_pwd = get_md5((password))
print("MD5加密后:{}".format(md5_pwd)) # e10adc3949ba59abbe56e057f20f883e
  • 加鹽

加鹽譬巫,是指通過對原始用戶密碼加一個復(fù)雜字符串后咖楣,然后再進(jìn)行MD5加密,另外芦昔,因為我們當(dāng)前設(shè)計的用戶名是唯一且無法修改的诱贿,所以可以把用戶名也放進(jìn)去進(jìn)行加密處理,以提高用戶密碼的安全性咕缎。

我們在項目根路徑下 config 包中珠十,修改文件 setting.py ,在該文件中配置MD5加密加鹽處理的鹽值 SALT凭豪,如下:

SALT = "test2020#%*"

同時焙蹭,我們在項目根路徑下 common 包中,新建文件 md5_operate.py 嫂伞,該文件下存放了 MD5加密加鹽 的代碼孔厉,如下:

import hashlib
from config.setting import MD5_SALT

def get_md5(username, str):
    """MD5加密處理"""
    str = username + str + MD5_SALT  # 把用戶名也作為str加密的一部分
    md5 = hashlib.md5()  # 創(chuàng)建md5對象
    md5.update(str.encode("utf-8"))  # Python3中需要先轉(zhuǎn)換為 bytes 類型,才能加密
    return md5.hexdigest()  # 返回密文

注冊用戶時MD5加密

@app.route("/register", methods=['POST'])
def user_register():
    """注冊用戶"""
    username = request.json.get("username", "").strip()  # 用戶名
    password = request.json.get("password", "").strip()  # 密碼
    sex = request.json.get("sex", "0").strip()  # 性別帖努,默認(rèn)為0(男性)
    telephone = request.json.get("telephone", "").strip()  # 手機號
    address = request.json.get("address", "").strip()  # 地址撰豺,默認(rèn)為空串
    if username and password and telephone: # 注意if條件中 "" 也是空, 按False處理
        sql1 = "SELECT username FROM user WHERE username = '{}'".format(username)
        res1 = db.select_db(sql1)
        print("查詢到用戶名 ==>> {}".format(res1))
        sql2 = "SELECT telephone FROM user WHERE telephone = '{}'".format(telephone)
        res2 = db.select_db(sql2)
        print("查詢到手機號 ==>> {}".format(res2))
        if res1:
            return jsonify({"code": 2002, "msg": "用戶名已存在,注冊失斊从唷N坭搿!匙监!"})
        elif not (sex == "0" or sex == "1"):
            return jsonify({"code": 2003, "msg": "輸入的性別只能是 0(男) 或 1(女)9讶蟆!舅柜!"})
        elif not (len(telephone) == 11 and re.match("^1[3,5,7,8]\d{9}$", telephone)):
            return jsonify({"code": 2004, "msg": "手機號格式不正確K笪啤!致份!"})
        elif res2:
            return jsonify({"code": 2005, "msg": "手機號已被注冊1涑椤!氮块!"})
        else:
            password = get_md5(username, password) # 把傳入的明文密碼通過MD5加密變?yōu)槊芪纳茉兀缓笤龠M(jìn)行注冊
            sql3 = "INSERT INTO user(username, password, role, sex, telephone, address) " \
                  "VALUES('{}', '{}', '1', '{}', '{}', '{}')".format(username, password, sex, telephone, address)
            db.execute_db(sql3)
            print("新增用戶信息SQL ==>> {}".format(sql3))
            return jsonify({"code": 0, "msg": "恭喜,注冊成功滔蝉!"})
    else:
        return jsonify({"code": 2001, "msg": "用戶名/密碼/手機號不能為空击儡,請檢查!r鹨阳谍!"})

在上面代碼中蛀柴,我們只在注冊之前增加了一行代碼:password = get_md5(username, password)乎完,先把請求參數(shù)中傳入的明文密碼進(jìn)行MD5加密囤攀,然后把密文用于注冊并寫入到數(shù)據(jù)庫中。

登錄用戶時MD5加密

@app.route("/login", methods=['POST'])
def user_login():
    """登錄用戶"""
    username = request.values.get("username", "").strip()
    password = request.values.get("password", "").strip()
    if username and password: # 注意if條件中空串 "" 也是空, 按False處理
        sql1 = "SELECT username FROM user WHERE username = '{}'".format(username)
        res1 = db.select_db(sql1)
        print("查詢到用戶名 ==>> {}".format(res1))
        if not res1:
            return jsonify({"code": 1003, "msg": "用戶名不存在2饽ⅰQ得病制肮!"})
        md5_password = get_md5(username, password) # 把傳入的明文密碼通過MD5加密變?yōu)槊芪?        sql2 = "SELECT * FROM user WHERE username = '{}' and password = '{}'".format(username, md5_password)
        res2 = db.select_db(sql2)
        print("獲取 {} 用戶信息 == >> {}".format(username, res2))
        if res2:
            timeStamp = int(time.time()) # 獲取當(dāng)前時間戳
            # token = "{}{}".format(username, timeStamp)
            token = get_md5(username, str(timeStamp)) # MD5加密后得到token
            redis_db.handle_redis_token(username, token) # 把token放到redis中存儲
            return_info = {  # 構(gòu)造一個字段,將 id/username/token/login_time 返回
                "id": res2[0]["id"],
                "username": username,
                "token": token,
                "login_time": time.strftime("%Y/%m/%d %H:%M:%S")
            }
            return jsonify({"code": 0, "login_info": return_info, "msg": "恭喜递沪,登錄成功豺鼻!"})
        return jsonify({"code": 1002, "msg": "用戶名或密碼錯誤!?羁拘领!"})
    else:
        return jsonify({"code": 1001, "msg": "用戶名或密碼不能為空!S5鳌!"})

上面代碼中届良,我們在登錄前對請求參數(shù)中的明文密碼進(jìn)行MD5加密:md5_password = get_md5(username, password)笆凌,然后再進(jìn)行登錄,而登錄成功后士葫,同樣先對 token 進(jìn)行MD5加密:token = get_md5(username, str(timeStamp))乞而,再存儲到redis中。

修改用戶請求接口實現(xiàn)

接下來慢显,我們準(zhǔn)備新開發(fā)個接口:修改用戶接口爪模。該接口需要 管理員用戶 登錄認(rèn)證后才可以進(jìn)行操作,管理員用戶可以修改任何用戶信息荚藻。但在修改用戶信息時屋灌,只允許修改 密碼 password、性別 sex应狱、手機號 telephone共郭、聯(lián)系地址 address 幾個字段的數(shù)據(jù)。

  • 修改用戶接口(PUT接口)

這個接口是通過 PUT 方式來進(jìn)行請求疾呻,在 Flask 中除嘹,如果要讓請求接口接口支持 PUT 請求方式,我們只需要在 methods 中設(shè)置就行岸蜗。

@app.route("/update/user/<int:id>", methods=['PUT'])
def user_update(id): # id為準(zhǔn)備修改的用戶ID
    """修改用戶信息"""
    username = request.json.get("username", "").strip() # 當(dāng)前登錄的管理員用戶
    token = request.json.get("token", "").strip()  # token口令
    new_password = request.json.get("password", "").strip()  # 新的密碼
    new_sex = request.json.get("sex", "0").strip()  # 新的性別尉咕,如果參數(shù)不傳sex,那么默認(rèn)為0(男性)
    new_telephone = request.json.get("telephone", "").strip()  # 新的手機號
    new_address = request.json.get("address", "").strip()  # 新的聯(lián)系地址璃岳,默認(rèn)為空串
    if username and token and new_password and new_telephone: # 注意if條件中空串 "" 也是空, 按False處理
        if not (new_sex == "0" or new_sex == "1"):
            return jsonify({"code": 4007, "msg": "輸入的性別只能是 0(男) 或 1(女)D甓小;诖贰!"})
        elif not (len(new_telephone) == 11 and re.match("^1[3,5,7,8]\d{9}$", new_telephone)):
            return jsonify({"code": 4008, "msg": "手機號格式不正確;蘅睢Q坠Α!"})
        else:
            redis_token = redis_db.handle_redis_token(username) # 從redis中取token
            if redis_token:
                if redis_token == token: # 如果從redis中取到的token不為空缓溅,且等于請求body中的token
                    sql1 = "SELECT role FROM user WHERE username = '{}'".format(username)
                    res1 = db.select_db(sql1)
                    print("根據(jù)用戶名 【 {} 】 查詢到用戶類型 == >> {}".format(username, res1))
                    user_role = res1[0]["role"]
                    if user_role == 0: # 如果當(dāng)前登錄用戶是管理員用戶
                        sql2 = "SELECT * FROM user WHERE id = '{}'".format(id)
                        res2 = db.select_db(sql2)
                        print("根據(jù)用戶ID 【 {} 】 查詢到用戶信息 ==>> {}".format(id, res2))
                        sql3 = "SELECT telephone FROM user WHERE telephone = '{}'".format(new_telephone)
                        res3 = db.select_db(sql3)
                        print("查詢到手機號 ==>> {}".format(res3))
                        if not res2: # 如果要修改的用戶不存在于數(shù)據(jù)庫中蛇损,res2為空
                            return jsonify({"code": 4005, "msg": "修改的用戶ID不存在,無法進(jìn)行修改坛怪,請檢查S倨搿!袜匿!"})
                        elif res3: # 如果要修改的手機號已經(jīng)存在于數(shù)據(jù)庫中更啄,res3非空
                            return jsonify({"code": 4006, "msg": "手機號已被注冊,無法進(jìn)行修改居灯,請檢查<牢瘛!怪嫌!"})
                        else:
                            # 如果請求參數(shù)不傳address义锥,那么address字段不會被修改,仍為原值
                            if not new_address:
                                new_address = res2[0]["address"]
                            # 把傳入的明文密碼通過MD5加密變?yōu)槊芪?                            new_password = get_md5(res2[0]["username"], new_password)
                            sql3 = "UPDATE user SET password = '{}', sex = '{}', telephone = '{}', address = '{}' " \
                                   "WHERE id = {}".format(new_password, new_sex, new_telephone, new_address, id)
                            db.execute_db(sql3)
                            print("修改用戶信息SQL ==>> {}".format(sql3))
                            return jsonify({"code": 0, "msg": "恭喜岩灭,修改用戶信息成功拌倍!"})
                    else:
                        return jsonify({"code": 4004, "msg": "當(dāng)前用戶不是管理員用戶,無法進(jìn)行操作噪径,請檢查V簟!找爱!"})
                else:
                    return jsonify({"code": 4003, "msg": "token口令不正確梗顺,請檢查!3瞪恪荚守!"})
            else:
                return jsonify({"code": 4002, "msg": "當(dāng)前用戶未登錄,請檢查A钒恪4Q!"})
    else:
        return jsonify({"code": 4001, "msg": "管理員用戶/token口令/密碼/手機號不能為空薄料,請檢查3ü薄!摄职!"})

相關(guān)的接口返回碼和請求場景如下:

接口返回碼 請求場景
0 請求參數(shù)正確誊役,修改用戶信息成功获列!
4001 請求參數(shù)中,管理員用戶/token口令/密碼/手機號蛔垢,任一參數(shù)為空
4002 請求參數(shù)中击孩,當(dāng)前操作用戶沒有token,登錄驗證失敗
4003 請求參數(shù)中的token值鹏漆,與redis中的token值不一致
4004 請求參數(shù)中巩梢,當(dāng)前操作用戶不是管理員用戶,無權(quán)限進(jìn)行操作
4005 請求參數(shù)中艺玲,要刪除的用戶ID不存在
4006 請求參數(shù)中括蝠,手機號已被其他人注冊使用
4007 請求參數(shù)中, sex 性別字段值不是 0 或 1
4008 請求參數(shù)中饭聚,手機號格式不正確

可參考如下進(jìn)行修改用戶接口請求( token 可以從用戶登錄成功后的接口返回數(shù)據(jù)中獲燃删):

請求方式:PUT
請求地址:http://127.0.0.1:5000/update/user/3
請求頭:
Content-Type: application/json

Body:{"username": "wintest", "token": "f54f9d6ebba2c75d45ba00a8832cb593", "sex": "1", "address": "廣州市天河區(qū)", "password": "12345678", "telephone": "13500010003"}
接口請求示例

OK,通過以上操作秒梳,我們已成功對用戶密碼和token串進(jìn)行了數(shù)據(jù)加密處理法绵,并實現(xiàn)了修改用戶的功能,相關(guān)代碼已上傳到GitHub酪碘,大家有興趣的可以基于此進(jìn)行學(xué)習(xí)及開展接口測試朋譬。

GitHub源碼地址:https://github.com/wintests/flaskDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市婆跑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌庭呜,老刑警劉巖滑进,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異募谎,居然都是意外死亡扶关,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門数冬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來节槐,“玉大人,你說我怎么就攤上這事拐纱⊥欤” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵秸架,是天一觀的道長揍庄。 經(jīng)常有香客問我,道長东抹,這世上最難降的妖魔是什么蚂子? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任沃测,我火速辦了婚禮,結(jié)果婚禮上食茎,老公的妹妹穿的比我還像新娘蒂破。我一直安慰自己,他們只是感情好别渔,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布附迷。 她就那樣靜靜地躺著,像睡著了一般钠糊。 火紅的嫁衣襯著肌膚如雪挟秤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天抄伍,我揣著相機與錄音艘刚,去河邊找鬼。 笑死截珍,一個胖子當(dāng)著我的面吹牛攀甚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播岗喉,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼秋度,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了钱床?” 一聲冷哼從身側(cè)響起荚斯,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎查牌,沒想到半個月后事期,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡纸颜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年兽泣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胁孙。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡唠倦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涮较,到底是詐尸還是另有隱情稠鼻,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布狂票,位于F島的核電站枷餐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜毛肋,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一怨咪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧润匙,春花似錦诗眨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至厂财,卻和暖如春芋簿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背璃饱。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工与斤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荚恶。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓撩穿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谒撼。 傳聞我的和親對象是個殘疾皇子食寡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355