【簡說Python WEB】用戶身份驗證--Werkzeug


系統環境:Ubuntu 18.04.1 LTS

Python使用的是虛擬環境:virutalenv

Python的版本:Python 3.6.9

【簡說Python WEB】用戶身份驗證--Werkzeug

基本大多數web應用都有用戶身份驗證。

基本的身份驗證,要不是用戶名,要不是電子郵件地址。加上自己的密碼。完成身份驗證。

這里就是做一個完整的用戶身份驗證系統

Flask的security擴展

  • FLask-Login:管理已經登錄的用戶會話
  • Werkzeug:計算密碼散列值,同時進行check
  • itsdangerous:生成並check加密安全令牌

使用Werkzeug生成密碼散列值

Werkzeug的security模塊實現了散列值的計算。有兩個函數,一個生成,另外一個核對

如下:

generate_password_hash(password,method='pbkdf2:sha256',salt_length=8)

三個輸入參數:

  • 第一個參數: 輸入密碼
  • 第二個參數:pbkdf2_sha256加密驗證算法
  • 第三個參數:salt值字符串長度。

pbkdf2_sha256 + SALT鹽值加密,是很可靠的一種加密方式。

輸入的值是一個密碼,輸出的值返回密碼散列值的字符串。基本默認值就夠用了。

check_password_hash(hash, password)

這個參數從數據庫中取出密碼的hash值和輸入的密碼值進行校對。如果返回為True說明輸入的密碼正確。

app/models.py加入Werkzeug密碼散列值

from werkzeug.security import generate_password_hash, check_password_hash
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)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

在shell測試上述代碼:

(zsdpy1) zsd@zsd-virtual-machine:~/Zflask$ flask shell
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0] on linux
App: app [production]
Instance: /home/zsd/Zflask/instance
>>> u = User()
>>> u.password = 'cat' 
>>> u.password_hash
'pbkdf2:sha256:150000$bCVGWsku$752d59b87a450aac1b2ea9297e6475f2300fcdea4b589f788aa753e1a820c12d'
>>> u.verify_password('cat')
True
>>> u.verify_password('zsd')
False
>>> u2 = User()
>>> u2.password = 'cat'
>>> u2.password_hash
'pbkdf2:sha256:150000$oMmeJziP$92900571f3639e0dca770bbb94f83c64a22d3f510343446a32499c2f64783962'

可以看到u和u2的密碼雖然都是cat,但是hash密碼值確實不一樣的。

這樣手動寫shell一步一步測試特別浪費時間,我們可以通過寫單元測試,完成測試工作。如下:

tests/test_user_model.py 密碼散列測試

import unittest
from app import create_app, db
from app.models import User


class UserModelTestCase(unittest.TestCase):
    def setUp(self):
        self.app = create_app('testing')
        self.app_context = self.app.app_context()
        self.app_context.push()
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()
        self.app_context.pop()

    def test_password_setter(self):
        u = User(password='cat')
        self.assertTrue(u.password_hash is not None)

    def test_no_password_getter(self):
        u = User(password='cat')
        with self.assertRaises(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):
        u = User(password='cat')
        u2 = User(password='cat')
        self.assertTrue(u.password_hash != u2.password_hash)

執行下列命令,做單元測試 :

(zsdpy1) $ flask test
test_app_exists (test_basics.BasicsTestCase) ... ok
test_app_is_testing (test_basics.BasicsTestCase) ... ok
test_no_password_getter (test_user_model.UserModelTestCase) ... ok
test_password_salts_are_random (test_user_model.UserModelTestCase) ... ok
test_password_setter (test_user_model.UserModelTestCase) ... ok
test_password_verification (test_user_model.UserModelTestCase) ... ok

----------------------------------------------------------------------
Ran 6 tests in 2.760s

這樣就相當於自動化測試,直接測試了剛剛shell做得測試工作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM