記一次《flask web 開發實戰》flask-login學習(不完全的小整理)
前景
主要問題
- flask-login 的流程
- session,cookie
- remember_me這個功能
第一步–編寫使用者類
使用者類需要包含四個方法
用於表示使用者的類需要實現這些方法:- is_authenticated()
當用戶通過驗證時,也即提供有效證明時返回 True 。(只有通過驗證的使用者 會滿足 login_required 的條件。) - is_active()
如果這是一個活動使用者且通過驗證,賬戶也已啟用,未被停用,也不符合任何你 的應用拒絕一個賬號的條件,返回 True 。不活動的賬號可能不會登入(當然, 是在沒被強制的情況下)。 - is_anonymous()
如果是一個匿名使用者,返回 True 。(真實使用者應返回 False 。) - get_id()
返回一個能唯一識別使用者的,並能用於從 user_loader 回撥中 載入使用者的 unicode 。注意著 必須 是一個 unicode ——如果 ID 原本是 一個 int 或其它型別,你需要把它轉換為 unicode 。
- is_authenticated()
要簡便地實現使用者類,你可以從 UserMixin 繼承,它提供了對所有這些方法的預設 實現。(雖然這不是必須的。)
第二步-初始化LonginManager
login_manager = LoginManager()
login_manager.session_protection = 'strong'
login_manager.login_view = 'auth.login'
首先初始化一個物件,然後進行配置
session_protection
session_protection有三種模式:None,basic,strong
- 用處:保護會話的,防止會話session被盜用,被啟用的時候在basic和strong兩種模式中執行預設為:basic
- 讀一波原始碼
def _session_protection(self):
sess = session._get_current_object()
ident = self._session_identifier_generator()
app = current_app._get_current_object()
mode = app.config.get('SESSION_PROTECTION' , self.session_protection)
# if the sess is empty, it's an anonymous user or just logged out
# so we can skip this
if sess and ident != sess.get('_id', None):
if mode == 'basic' or sess.permanent:
sess['_fresh'] = False
session_protected.send(app)
return False
elif mode == 'strong':
for k in SESSION_KEYS:
sess.pop(k, None)
sess['remember'] = 'clear'
session_protected.send(app)
return True
return False
登入的時候,直接將user_id寫入session,session裡面有user_id就是登入的,並且標記這個使用者是新鮮的,就是通過登入的,而不是用的cookie。
在strong模式下,當之前瀏覽器關閉的時候,session裡面的內容都會刪除,只寫入一個remember欄位為clear,第二次登入時候
app.after_request(self._update_remember_cookie)
def _update_remember_cookie(self, response):
# Don't modify the session unless there's something to do.
if 'remember' in session:
operation = session.pop('remember', None)
if operation == 'set' and 'user_id' in session:
self._set_cookie(response)
elif operation == 'clear':
self._clear_cookie(response)
return response
首先session中的remember作為一個單獨的cookie寫入response,然後傳給前端,此時的remember欄位由於session中的remember已經被清除,寫上了clear,所以清楚了cookie,並傳給前端(怎麼不清除?改成basic模式,只顯示非fresh使用者,但是可以繼續用cookie)
- 第一次登入
- 關閉瀏覽器之後登入
- 重新整理瀏覽器之後登入
PS:圖片來自網上,過兩天附上自己實驗
對於cookie的過期時間修改等,先留上線索,過兩天會用到
login_view
設定登入檢視的名稱,如果一個未登入使用者請求一個只有登入使用者才能訪問的檢視,則閃現一條錯誤訊息預設為
Please log in to access this page
並重定向到這裡設定的登入檢視。如果未設定登入檢視,則直接返回401錯誤。也可以自己設定錯誤訊息
login_manager.login_message = u"Bonvolu ensaluti por uzi tio paĝo."
第三步,回撥函式
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
解讀:
在每次請求過來後,Flask-Login都會從Session中尋找”user_id”的值,如果找到的話,就會用這個”user_id”值來呼叫此回撥函式就是login_manager 中使用user_loader裝飾器設定的callback函式直接獲取當前登入的使用者,從會話中儲存的使用者 ID 重新載入使用者物件的資訊。然後返回到一開始的那個需要登入才能進入的介面。
第四步,登入使用者檢視函式login()部分
login_user(user, form.remember_me.data)
login_user() 函式的引數是要登入的使用者,以及可選的“記住我”布林值,“記住我”也在表單中填寫。如果值為 False ,那麼關閉瀏覽器後用戶會話就過期了,所以下次使用者訪問時要重新登入。如果值為 True ,那麼會在使用者瀏覽器中寫入一個長期有效的 cookie,使用這個 cookie 可以復現使用者會話。
return redirect(request.args.get('next') or url_for('main.index'))
使用者訪問未授權的 URL 時會顯示登入表單,Flask-Login會把原地址儲存在查詢字串的 next 引數中,這個引數可從 request.args 字典中讀取。如果查詢字串中沒有 next 引數,則重定向到首頁。
理解:這第一段的話好理解,第二段的意思是當訪問需要登入的介面page1時,成功完成登入之後,會設定完cookie,然後返回到之前需要登入才能訪問的介面page1,這個地址儲存在request.args字典裡面,沒有的話就回到首頁
總結
這次的最大最關鍵的問題還在cookie和session了,它們的原理,至今還未搞清,尤其是session的部分,之後還需要進一步作為深入。今天只是初步熟悉一下flask-login,過兩天要完成登入的介面,併成功完成上述待驗證的部分,特做此記錄。對於我這樣的小白來說,路還很長啊~最好的提升看來還是讀原始碼加上別人的講解。