摘要:最后我們看下這個方法主要是清除了和中的關鍵參數,比如時設置的以及等,清除后又調用了,根據之前的邏輯,當然不可能重載成功,因為已經為了,執行到就已經結束了,其實算是這個模塊中很關鍵的一個函數,這個類也是這個模塊的核心所在,以后有時間繼續研究。
今天看書遇到了flask login模塊中的信號機制,看到user_loader這個裝飾器時有些疑惑,為什么需要這個裝飾器呢,先看一下源碼:
def user_loader(self, callback): """ This sets the callback for reloading a user from the session. The function you set should take a user ID (a ``unicode``) and return a user object, or ``None`` if the user does not exist. :param callback: The callback for retrieving a user object. :type callback: callable """ self.user_callback = callback return callback
看到這不禁疑惑,它的作用只是將被它包裝的函數存到self.user_callback這個屬性中去,我們先到login_user這個登陸函數中去看看:
def login_user(user, remember=False, duration=None, force=False, fresh=True): if not force and not user.is_active: return False user_id = getattr(user, current_app.login_manager.id_attribute)() session["user_id"] = user_id session["_fresh"] = fresh session["_id"] = current_app.login_manager._session_identifier_generator() if remember: session["remember"] = "set" if duration is not None: try: # equal to timedelta.total_seconds() but works with Python 2.6 session["remember_seconds"] = (duration.microseconds + (duration.seconds + duration.days * 24 * 3600) * 10**6) / 10.0**6 except AttributeError: raise Exception("duration must be a datetime.timedelta, " "instead got: {0}".format(duration)) _request_ctx_stack.top.user = user user_logged_in.send(current_app._get_current_object(), user=_get_user()) return True
可以看到,login_user這個函數接受user這個主要的參數,getattr(user, current_app.login_manager.id_attribute)()這句是為了調用user中的get_id方法
self.id_attribute = ID_ATTRIBUTE ID_ATTRIBUTE = "get_id"
注意在getattr后面還有個()所以會調用對應的方法,所以user_id中就存放了登陸用戶的id號,并寫入到session中去,如果設置了remember為True的話,關掉瀏覽器重新打開后,用戶不會退出,函數的最后_request_ctx_stack.top.user = user,將當前user加入到請求上下文的棧頂,就能用current_user獲取了。
上面說到self.user_callback已經存了被user_loader裝飾的函數,那么在哪里用到了它呢,我在login_manager.py中查找,發現只有一個方法使用到了這個熟悉,這個方法是reload_user():
def reload_user(self, user=None): """ This set the ctx.user with the user object loaded by your customized user_loader callback function, which should retrieved the user object with the user_id got from session. Syntax example: from flask_login import LoginManager @login_manager.user_loader def any_valid_func_name(user_id): # get your user object using the given user_id, # if you use SQLAlchemy, for example: user_obj = User.query.get(int(user_id)) return user_obj Reason to let YOU define this self.user_callback: Because we won"t know how/where you will load you user object. """ ctx = _request_ctx_stack.top if user is None: user_id = session.get("user_id") if user_id is None: ctx.user = self.anonymous_user() else: if self.user_callback is None: raise Exception( "No user_loader has been installed for this " "LoginManager. Refer to" "https://flask-login.readthedocs.io/" "en/latest/#how-it-works for more info.") user = self.user_callback(user_id) if user is None: ctx.user = self.anonymous_user() else: ctx.user = user else: ctx.user = user
它先從請求上下文中取出最新的請求,如果沒有傳入user,那么會從session中試圖取出對應的user_id,這是一種保護機制,不使用cookie,而使用session,user_id在login時會寫入session,如果登陸時remember參數傳入了True,那么關閉瀏覽器重新打開后session["user_id"]將不會被清除,這時候也就可以獲取到了,如果登陸時沒有設置remember為True,那么關閉瀏覽器后user_id會被設為None,則ctx.user = self.anonymous_user(),棧頂的用戶為匿名用戶,也就需要重新登陸了;取出了user_id,并且self.user_callback不為空,則會調用被user_loader裝飾的函數,并傳入user_id,在被裝飾的函數中我們要根據這個user_id來查找并返回對應的用戶實例,如果成功返回,那么當前請求上下文棧頂的用戶就設置為返回的用戶。
你可能會問,為什么要重載用戶呢?因為http協議是無狀態的,每次都會發送一個新的請求,請求上下文的棧頂會被新的請求覆蓋,對應的user屬性也就沒了,所以需要通過reload_user重載上一次記錄在session中并且未被清除的用戶,重載失敗則需要重新登陸,這也就是這個裝飾器的作用了。
最后我們看下logout_user()這個方法:
def logout_user():
""" Logs a user out. (You do not need to pass the actual user.) This will also clean up the remember me cookie if it exists. """ user = _get_user() if "user_id" in session: session.pop("user_id") if "_fresh" in session: session.pop("_fresh") cookie_name = current_app.config.get("REMEMBER_COOKIE_NAME", COOKIE_NAME) if cookie_name in request.cookies: session["remember"] = "clear" if "remember_seconds" in session: session.pop("remember_seconds") user_logged_out.send(current_app._get_current_object(), user=user) current_app.login_manager.reload_user() return True
logout主要是清除了session和cookie中的關鍵參數,比如login時設置的user_id以及remember等,清除后又調用了reload_user(),根據之前的邏輯,當然不可能重載成功,因為user_id已經為None了,執行到ctx.user = self.anonymous_user()就已經結束了,其實reload_user算是這個模塊中很關鍵的一個函數,login_manager這個類也是這個模塊的核心所在,以后有時間繼續研究。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/44733.html
摘要:自行定義的方法用于權限判斷繼承至該類的用戶模型將作為未登陸時的用戶模型可以保持代碼的一致性。但是這樣的方法很危險,很造成一些其它項目的兼容性問題。打開頁面,顯示正常。 flask 相對于很多國企的 oracle 數據庫而言,是比較新的,因此很多古老的設計并不一定適合較新的 flask 的標準,但作為后來者,你得向前兼容,你得適應需求。本章內容就來解釋一下上一章——基于 oracle 的...
摘要:混雜著工作室圖片網任務截至今天終于完成了暑假另一個任務把考核任務按照狗書再寫一遍受益匪淺,路途荊棘叢生。。。。 混雜著工作室圖片網任務,截至今天終于完成了暑假另一個任務把考核任務按照狗書再寫一遍受益匪淺,路途荊棘叢生。。。。這里主要記錄了增加的功能,更多的可以看源代碼代碼在線預覽 上傳頭像404 Flask上傳文件我實現的主要思路就是,上傳文件到服務器,然后讀取文件當然你可以用二進制...
摘要:為字段賦值,返回給客戶端進行重定向總結一個視圖函數的如果不設置那么就是視圖函數名。為和搭起橋梁,使得整個后端框架更加靈活。返回的是視圖函數對應的,是對應視圖函數裝飾器傳入的值。 還是先來看看源碼 def route(self, rule, **options): A decorator that is used to register a view function for a...
摘要:今天看到的提問關于裝飾模式引發的思考又想起了。其實,模式就是裝飾器模式。這就造成了和裝飾器模式的一個本質不同基于類,還是基于對象。 今天看到 @chengxuyuan_329633 的提問 關于裝飾模式引發的思考 又想起了 mixin。mixin 模式和裝飾器模式很相似。 其實,mixin模式就是裝飾器模式。 那么單利模式呢?呵呵,其實就是全局變量/對象。 當過程式開發變得越來越...
閱讀 1877·2021-11-19 09:40
閱讀 2594·2021-08-30 09:46
閱讀 2177·2021-08-03 14:01
閱讀 2648·2019-08-30 10:54
閱讀 1198·2019-08-29 16:38
閱讀 1440·2019-08-29 11:02
閱讀 2536·2019-08-28 18:16
閱讀 1679·2019-08-28 18:09