《Flask Web開發:基於Python的Web應用開發實戰》學習筆記(二)

強大的石頭發表於2018-03-06

轉載於:http://pdf.us/2017/10/05/492.html,感謝這位大神

《Flask Web開發:基於Python的Web應用開發實戰》學習筆記

這裡是第二部分的學習筆記。第二部分:例項:社交部落格程式

第八章 使用者認證

用到的擴充套件

Flask-Login:管理已登入使用者的使用者會話
Werkzeug:計算密碼雜湊並核對
istdangerous:生成並核對加密安全令牌Flask-Mail:傳送與認證相關的密碼
Flask-Bootstrap:HTML模板
Flask-WTF:Web表單
使用Werkzeug實現密碼雜湊

Werkzeug的security模組可以實現計算密碼雜湊。主要用於使用者註冊和驗證使用者。

generate_password_hash(password,method=pbkdf2:sha1,salt_length=8)  以密碼作為輸入,輸出密碼的雜湊值

check_password_hash(hash,password)  返回True即表示驗證通過

程式從7a版本開始推進。資料庫改用mysql。先不要建表,db init;db migrate;db upgrade生成當前資料庫。

對app/models.py中User模型做改造:

關於@property@password.setter裝飾器
把一個getter方法變成屬性,只需要加上@property就可以了,此時,@property本身又建立了另一個裝飾器@password.setter,負責把一個setter方法變成屬性賦值
簡單講,@property附加到那個方法上,該方法變為同名屬性,並只具有讀屬性
而要設定屬性的值,需要使用另外一個方法,並附加@方法名.setter,這樣提供了寫屬性
一句話就是對屬性讀寫分別處理,如果沒有setter,則屬性為只讀

hash後的加密串,即使相同的密碼加密,hash串也不相同

該功能的單元測試用例:

建立認證藍本

對於不同的程式功能,使用不同的藍本,這樣可以使程式碼保持整齊有序。

藍本:auth/__init__.py

auth/views.py

auth/login.html位於app/templates/目錄下。當然,藍本也可以定義自己的模板資料夾,此時,render_template()會先搜尋程式資料夾,再搜尋藍本配置的模板資料夾。

在create_app函式中附加藍本auth到程式:app/__init__.py

url_prefix是可選引數,使用該引數後,藍本中定義的所有路由都會加上指定字首,這裡,/login變成了/auth/login。

使用Flask-Login認證使用者

pip install flask-login

使用Flask-Login擴充套件,User模型需要實現如下幾個方法:

屬性/方法說明
is_authenticated若使用者已登入,則返回True,否則返回False
is_active若允許使用者登入,則返回True,否則返回False;禁用使用者,可返回False
is_anonymous對普通使用者返回False
get_id()必須返回使用者唯一識別符號,使用Unicode編碼

這四個方法可以直接在User類中實現,更簡單的方法是使用Flask-Login提供的UserMixin類。

app/modles.py

初始化:app/__init__.py

session_protection可設定為None,'basic','strong',當設定為‘strong'時,會記錄客戶端IP和瀏覽器使用者代理資訊,發現異動就登出使用者。

Flask-Login要求實現一個回撥函式,使用指定的識別符號載入使用者:app/models.py

回撥函式接收以Unicode字串形式表示的使用者識別符號,若存在該使用者,則返回使用者物件,否則返回None

保護路由

讓一個路由僅讓認證的使用者能訪問,未認證使用者訪問,Flask-Login會攔截請求,把使用者發往登入頁面,示例如下:

新增登入表單

app/auth/forms.py

app/templates/base.html

<ul class="nav navbar-nav navbar-right">
{% if current_user.is_authenticated %}
<li><a href="{{ url_for('auth.logout') }} ">Sign Out</a></li>
{% else %}
<li><a href="{{ url_for('auth.login') }}">Sign In</a></li>
{% endif %}
</ul>

current_user由Flask-Login定義, 在檢視函式和模板中自動可用,這個變數的值是當前登入的使用者,若未登入,則是匿名使用者代理對像。

登入使用者

app/auth/views.py

app/templates/auth/login.html

 

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky - Login{% endblock %}

{% block page_content %}
<div class="page-header">
<h1>Login</h1>
</div>
<div class="col-md-4">
{{ wtf.quick_form(form) }}
</div>
{% endblock %}

 

登出使用者

app/auth/views.py

測試登入

shell中註冊新使用者

>>> u=User(email='admin@qq.com',username='ma',password='admin')
>>> db.session.add(u)
>>> db.session.commit()
{% if current_user.is_authenticated %}
{{ current_user.username }}
{% else %}
Stranger
{% endif %}
註冊新使用者

使用者登錄檔單:

注意,validator是複數:validators

其中,驗證函式Regexp是正規表示式驗證,第一個引數是正規表示式(包含字母、數字、下劃線和點),第二個是表示式的旗標(通常為0),第三個是匹配失敗時的錯誤訊息。

密碼的驗證使用EqualTo,放到任意一個就可以,另一個欄位做為引數傳入。

自定義的驗證函式:以validate_開頭,後面跟欄位名的方法。該方法會和常規驗證函式一起呼叫。

登錄檔單的渲染:

{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}

註冊新使用者的檢視函式:

確認帳戶

驗證郵箱,通過點選包含令牌的URL,修改標記狀態。

itsdangerous提供多種生成令牌方法,其中TimedJSONWebSignatureSerializer類生成具有過期時間的JSON Web簽名,該類建構函式接收引數是一個金鑰和過期時間(秒)。dumps方法為指定資料生成加密的令牌字串,load方法解碼令牌。

python manage.py shell
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
s=Serializer(app.config['SECRET_KEY'],expires_in=3600)
token=s.dumps({'confirm':23})   #生成token,簽名字串
data=s.loads(token)                   #data={u'confirm':23}

修改模型:app/models.py

傳送確認郵件

app/auth/views.py

因為只有提交資料庫後才能夠得到新使用者id,而生成token需要用到使用者id,所以需要新增db.session.commit()

模板:{{ url_for('auth.confirm',token=token,_external=True) }}

確認token:

藍本中的程式全域性請求鉤子-before_app_request

重新傳送確認郵件

管理帳戶

修改密碼

重設密碼

修改電子郵件

先確認郵件進行確認,輸入新郵件地址後,向該郵件地址傳送一封包含令牌的郵件。伺服器傳送令牌前,可先將郵件地址存到臨時表或者是直接存到token中。

第九章 使用者角色

角色在資料庫中的表示

app/models.py,新增兩個屬性

default = db.Column(db.Boolean,default=False,index=True)
permissions = db.Column(db.Integer)

其中permissions欄位使用二進位制位表示不同的許可權。

許可權常量:

class Permission:
FOLLOW=0x01                                 #0b00000001關注其它使用者
COMMENT=0x02                             #0b00000010在他人文章後發表評論
WRITE_ARTICLES=0x04                    #0b00000100寫文章
MODERATE_COMMENTS=0x08       #0b00001000管理他人發表的評論
ADMINISTER=0x80                           #0b10000000管理員

使用者角色:

使用者角色許可權許可權說明
匿名0b000000000x00未登入使用者,僅閱讀許可權
使用者0b000001110x07寫文章,寫評論,關注其他使用者
協管員0b000011110x0f增加管理他人評論功能
管理員0b111111110xff所有許可權,包括修改其它使用者許可權

通過insert_roles方法新增角色,使用shell操作,Role.insert_roles()

賦予角色

app/models.py

角色驗證

新增輔助方法:app/models.py

can方法使用位與操作,檢查使用者許可權。Anonymous類出於一致性考慮,無論使用者是否登入,均可使用current_user.can()和current_user.is_administrator()方法來驗證使用者許可權。

檢查使用者許可權的自定義修飾器

app/decorators.py

自定義修飾器的使用方法

模板中也需要檢查許可權,為避免每次呼叫render_template()時都多新增一個模板引數,可以使用上下文處理器,上下文處理器能讓變數在所有模板中全域性可訪問

app/main/__init__.py

@main.app_context_processor
def inject_permissions():
return dict(Permission=Permission)

第十章 使用者資料

資料資訊

相關文章