pythonjinja2if
❶ 如何在python Flask框架中運行重復任務
Flask是一個使用Python編寫的輕量級Web應用框架,憑借更靈活、輕便、安全且容易上手的特性,成為企業常用的Python框架之一。在完成Web前端、Linux以及MySQL相關的課程之後,專業的杭州Python學習班都會講解Flask框架知識,以下是整理的相關知識點。
Flask是一個基於Python開發並且依賴jinja2模板和Werkzeug WSGI服務的一個微型框架,對於Werkzeug本質是Socket服務端,其用於接收http請求並對請求進行預處理,然後觸發Flask框架。開發人員基於Flask框架提供的功能對請求進行相應的處理,並返回給用戶,如果要返回給用戶復雜的內容時,需要藉助jinja2模板來實現對模板的處理,即:將模板和數據進行渲染,將渲染後的字元串返回給用戶瀏覽器。
默認情況下,Flask不包含資料庫抽象層、表單驗證,或是其它任何已有多種庫可以勝任的功能。然而,Flask支持用擴展來給應用添加這些功能,如同是Flask本身實現的一樣。眾多的擴展提供了資料庫集成、表單驗證、上傳處理、各種各樣的開放認證技術等功能。
Flask框架的特點:
1)Flask自由、靈活,可擴展性強,第三方庫的選擇面廣,開發時可以結合自己最喜歡用的輪子,也能結合最流行最強大的Python庫;
2)入門簡單,即便沒有多少web開發經驗,也能很快做出網站;
3)非常適用於小型網站;
4)非常適用於開發Web服務的API;
5)開發大型網站無壓力,但代碼架構需要自己設計,開發成本取決於開發者的能力和經驗。
Flask框架運行解釋
1.app = Flask(__name__)
創建Flask對象app,Flask類的構造函數只有一個必須指定的參數,即程序主模塊或包的名字。在大多數程序中,Python的__name__變數就是所需要的值。
[email protected]('/')
web瀏覽器把請求發送給Web伺服器,Web伺服器再把請求發送給Flask程序實例。程序實例需要知道對每個URL請求運行哪些代碼,所以保存了一個URL到Python函數的映射關系。處理URL和函數之間的關系的程序稱為路由。在Flask程序中定義路由的最簡便方式,是使用程序實例提供的app.route修飾器,把修飾的函數注冊為路由。route()裝飾器告訴 Flask什麼樣的URL 能觸發我們的函數。這和Java中的注釋有異曲同工之妙。修飾器是Python語言的標准特性,可以使用不同的方式修改函數的行為。慣常用法是使用修飾器把函數注冊為事件的處理程序。
3.def index():函數
index()函數放在@app.route('/')後面,所以就是把index()函數注冊為路由。如果部署程序的伺服器域名為http://127.0.0.1:5000/,在瀏覽器中訪問http://127.0.0.1:5000/後,會觸發伺服器執行index()函數。
[email protected]('/user/')
同@app.route('/'),如果部署程序的伺服器域名為http://127.0.0.1:5000/,在瀏覽器中訪問http://127.0.0.1:5000/後,會觸發伺服器執行下方修飾函數。
5.app.run(debug=True)
程序實例用run方法啟動Flask繼承Web伺服器。
6.if __name__ == '__main__'
當Python解釋器,讀py文件,它會執行它發現的所有代碼。在執行代碼之前,它會定義一些變數。例如,如果這個py文件就是主程序,它會設置__name__變數為"__main__"。如果這個py被引入到別的模塊,__name__會被設置為該模塊的名字。
❷ 在Python中使用HTML模版的教程
這篇文章主要介紹了在Python中使用HTML模版的教程,HTML模版也是Python的各大框架下的一個基本功能,需要的朋友可以參考下。Web框架把我們從WSGI中拯救出來了。現在,我們只需要不斷地編寫函數,帶上URL,就可以繼續Web App的開發了。
但是,Web App不僅僅是處理邏輯,展示給用戶的頁面也非常重要。在函數中返回一個包含HTML的字元串,簡單的頁面還可以,但是,想想新浪首頁的6000多行的HTML,你確信能在Python的字元串中正確地寫出來么?反正我是做不到。
俗話說得好,不懂前端的Python工程師不是好的產品經理。有Web開發經驗的同學都明白,Web App最復雜的部分就在HTML頁面。HTML不僅要正確,還要通過CSS美化,再加上復雜的JavaScript腳本來實現各種交互和動畫效果。總之,生成HTML頁面的難度很大。
由於在Python代碼里拼字元串是不現實的,所以,模板技術出現了。
使用模板,我們需要預先准備一個HTML文檔,這個HTML文檔不是普通芹腔的HTML,而是嵌入了一些變數和指令,然後,根據我們傳入的數據,替換後嫌嫌衫,得到最終的HTML,發送給用戶:
這就是傳說中的MVC:Model-View-Controller,中文名「模型-視圖-控制器」。
Python處理URL的函數就是C:Controller,Controller負責業務邏輯,比如檢查用戶名是否存在,取出用戶信息等等;
包含變數{{ name }}的模板就是V:View,View負責顯示邏者枝輯,通過簡單地替換一些變數,View最終輸出的就是用戶看到的HTML。
MVC中的Model在哪?Model是用來傳給View的,這樣View在替換變數的時候,就可以從Model中取出相應的數據。
上面的例子中,Model就是一個dict:
{ name: Michael }
只是因為Python支持關鍵字參數,很多Web框架允許傳入關鍵字參數,然後,在框架內部組裝出一個dict作為Model。
現在,我們把上次直接輸出字元串作為HTML的例子用高端大氣上檔次的MVC模式改寫一下:
16
17
18
19
20
21
22
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route(/, methods=[GET, POST])
def home():
return render_template(home.html)
@app.route(/signin, methods=[GET])
def signin_form():
return render_template(form.html)
@app.route(/signin, methods=[POST])
def signin():
username = request.form[username]
password = request.form[password]
if username==admin and password==password:
return render_template(signin-ok.html, username=username)
return render_template(form.html, message=Bad username or password, username=username)
if __name__ == __main__:
app.run()
Flask通過render_template()函數來實現模板的渲染。和Web框架類似,Python的模板也有很多種。Flask默認支持的模板是jinja2,所以我們先直接安裝jinja2:
?
1
$ easy_install jinja2
然後,開始編寫jinja2模板:
?
1
home.html
用來顯示首頁的模板:
11
html
head
titleHome/title
/head
body
h1 style=font-style:italicHome/h1
/body
/html
form.html
用來顯示登錄表單的模板:
16
17
18
html
head
titlePlease Sign In/title
/head
body
{% if message %}
p style=color:red{{ message }}/p
{% endif %}
form action=/signin method=post
legendPlease sign in:/legend
pinput name=username placeholder=Username value={{ username }}/p
pinput name=password placeholder=Password type=password/p
pbutton type=submitSign In/button/p
/form
/body
/html
signin-ok.html
登錄成功的模板:
?
7
8
html
head
titleWelcome, {{ username }}/title
/head
body
pWelcome, {{ username }}!/p
/body
/html
登錄失敗的模板呢?我們在form.html中加了一點條件判斷,把form.html重用為登錄失敗的模板。
最後,一定要把模板放到正確的templates目錄下,templates和app.py在同級目錄下:
啟動python app.py,看看使用模板的頁面效果:
通過MVC,我們在Python代碼中處理M:Model和C:Controller,而V:View是通過模板處理的,這樣,我們就成功地把Python代碼和HTML代碼最大限度地分離了。
使用模板的另一大好處是,模板改起來很方便,而且,改完保存後,刷新瀏覽器就能看到最新的效果,這對於調試HTML、CSS和JavaScript的前端工程師來說實在是太重要了。
在Jinja2模板中,我們用{{ name }}表示一個需要替換的變數。很多時候,還需要循環、條件判斷等指令語句,在Jinja2中,用{% ... %}表示指令。
比如循環輸出頁碼:
?
1
2
3
{% for i in page_list %}
a href=/page/{{ i }}{{ i }}/a
{% endfor %}
如果page_list是一個list:[1, 2, 3, 4, 5],上面的模板將輸出5個超鏈接。
除了Jinja2,常見的模板還有:
Mako:用和${xxx}的一個模板;
Cheetah:也是用和${xxx}的一個模板;
Django:Django是一站式框架,內置一個用{% ... %}和{{ xxx }}的模板。
小結
有了MVC,我們就分離了Python代碼和HTML代碼。HTML代碼全部放到模板里,寫起來更有效率。
❸ 如何找到安裝python-jinja2等包
編輯環境:
[root@openstack-01 rhel7.x]# cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
openstack版本:Mitaka
python-zope-interface
python-jinja2
python-cheetah
python-cheetah
python-webtest
python-werkzeug
其中安裝python-jinja2的時候出現不兼容的問題:
[root@openstack-01 rhel7.x]# yum install python-jinja2-2.7.2
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
* c7-media:
Resolving Dependencies
--> Running transaction check
---> Package python-jinja2.noarch 0:2.7.2-1.el6 will be installed
--> Processing Dependency: python(abi) = 2.6 for package: python-jinja2-2.7.2-1.el6.noarch
--> Finished Dependency Resolution
Error: Package: python-jinja2-2.7.2-1.el6.noarch (RHEL-Repository)
Requires: python(abi) = 2.6
Installed: python-2.7.5-34.el7.x86_64 (@anaconda)
python(abi) = 2.7
python(abi) = 2.7
You could try using --skip-broken to work around the problem
You could try running: rpm -Va --nofiles --nodigest
[root@openstack-01 yum]# yum install python-2.6.6
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
* c7-media:
Package matching python-2.6.6-51.el6.x86_64 already installed. Checking for update.
Nothing to do
,具體解決方案如下:
解決方案1:
我想這個問題主要是如何解決python-2.7.5-34.el7.x86_64和python-2.6.6-51.el6.x86_64的問題。
CentOS Linux release 7.2.1511自帶的是python-2.7.5-34.el7.x86_64。
下面的包都要2.6
python-zope-interface
python-jinja2
python-cheetah
python-cheetah
python-webtest
python-werkzeug
解決方案2:
官網上也有這個問題,可是沒有人回答。
https://ask.openstack.org/zh/question/91784/zai-centos7zhong-an-zhuang-havanati-shi-pythonban-ben-bu--chi/
❹ 純 Python 寫一個 Web 框架,就是這么簡單
造輪子是最好的一種學習方式,本文嘗試從0開始造個Python Web框架的輪子,我稱它為 ToyWebF 。
本文操作環境為:MacOS,文中涉及的命令,請根據自己的系統進行替換。
ToyWebF的簡單特性:
下面我們來實現這些特性。
首先,我們需要安裝gunicorn,回憶一下Flask框架,該框架有內置的Web伺服器,但不穩定,所以上線時通常會替換成uWSGI或gunicorn,這里不搞這個內置Web服務,直接使用gunicorn。
我們創建新的目錄與Python虛擬環境,在該虛擬環境中安裝gunicorn
在啥都沒有的情況下,構建最簡單的Web服務,在ToyWebF目錄下,創建app.py與api.py文件,寫入下面代碼。
運行 gunicorn app:app 訪問 http://127.0.0.1:8000 ,可以看見 Hello, World! ,但現在請求體中的參數在environ變數中,難以解析,我們返回的response也是bytes形式。
我們可以使用webob庫,將environ中的數據轉為Request對象,將需要返回的數據轉為Response對象,處理起來更加直觀方便,直接通過pip安裝一下。
然後修改一下API類的 __call__方法 ,代碼如下。
上述代碼中,通過webob庫的Request類將environ對象(請求的環境信息)轉為容易處理的request,隨後調用handle_request方法對request進行處理,處理的結果,通過response對象返回。
handle_request方法在ToyWebF中非常重要,它會匹配出某個路由對應的處理方法,然後調用該方法處理請求並將處理的結果返回,在解析handle_request前,需要先討論路由注冊實現,代碼如下。
其實就是將路由和方法存到self.routes字典中,可以通過route裝飾器的形式將路由和方法關聯,也可以通過add_route方法關聯,在app.py中使用一下。
因為url中可以存在變數,如 @app.route("/hello/{name}") ,所以在匹配時,需要進行解析,可以使用正則匹配的方式進行匹配,parse這個第三方庫已經幫我們實現了相應的正則匹配邏輯,pip安裝使用一下則可。
這里定義find_handler方法來實現對self.routes的遍歷。
了解了路由與方法關聯的原理後,就可以實現handle_request方法,該方法主要的路徑就是根據路由調度對應的方法,代碼如下。
在該方法中,首先實例化webob庫的Response對象,然後通過self.find_handler方法獲取此次請求路由對應的方法和對應的參數,比如。
它將返回hello方法對象和name參數,如果是 /hello/二兩 ,那麼name就是二兩。
因為route裝飾器可能裝飾器的類對象,比如。
此時self.find_handler方法返回的hanler就是個類,但我們希望調用的是類中的get、post、delete等方法,所以需要一個簡單的判斷邏輯,通過inspect.isclass方法判斷handler如果是類對象,那麼就通過getattr方法獲取類對象實例的中對應的請求方法。
如果類對象中沒有該方法屬性,則拋出該請求類型不被允許的錯誤,如果不是類對象或類對象中存在該方法屬性,則直接調用則可。
此外,如果方法的路由並沒有注冊到self.routes中,即404的情況,定義了defalut_response方法返回其中內容,代碼如下。
如果handle_request方法中調度的過程出現問題,則直接raise將錯誤拋出。
至此,一個最簡單的web服務就編寫完成了。
回顧Flask,Flask可以支持HTML、CSS、JavaScript等靜態文件,利用模板語言,可以構建出簡單但美觀的Web應用,我們讓TopWebF也支持這一功能,最終實現圖中的網站,完美兼容靜態文件。
Flask使用了jinja2作為其html模板引擎,ToyWebF同樣使用jinja2,jinja2其實實現一種簡單的DSL(領域內語言),讓我們可以在HTML中通過特殊的語法改變HTML的結構,該項目非常值得研究學習。
首先 pip install jinja2 ,然後就可以使用它了,在ToyWebF項目目錄中創建templates目錄,以該目錄作為默認的HTML文件根目錄,代碼如下。
首先利用jinja2的FileSystemLoader類將file system中的某個文件夾作為loader,然後初始化Environment。
在使用的過程中(即調用template方法),通過get_template方法獲得具體的某個模板並通過render方法將對應的內容傳遞給模板中的變數。
這里我們不寫前端代碼,直接去互聯網中下載模板,這里下載了Bootstrap提供的免費模板,可以自行去 https://startbootstrap.com/themes/freelancer/ 下載,下載完後,你會獲得index.html以及對應的css、jss、img等文件,將index.html移動到ToyWebF/templates中並簡單修改了一下,添加一些變數。
然後在app.py文件中為index.html定義路由以及需要的參數。
至此html文件的支持就完成了,但此時的html無法正常載入css和js,導致頁面布局非常醜陋且交互無法使用。
接著就讓ToyWebF支持css、js,首先在ToyWebF目錄下創建static文件夾用於存放css、js或img等靜態文件,隨後直接將前面下載的模板,其中的靜態文件復制到static中則可。
通過whitenoise第三方庫,可以通過簡單的幾行代碼讓web框架支持css和js,不需要依賴nginx等服務,首先 pip install whitenoise ,隨後修改API類的 __init__ 方法,代碼如下。
其實就是通過WhiteNoise將self.wsgi_app方法包裹起來,在調用API的 __call__ 方法時,直接調用self.whitenoise。
此時,如果請求web服務獲取css、js等靜態資源,WhiteNoise會獲取其內容並返回給client,它在背後會匹配靜態資源在系統中對應的文件並將其讀取返回。
至此,一開始的網頁效果就實現好了。
web服務如果出現500時,默認會返回 internal server error ,這顯得比較丑,為了讓框架使用者可以自定義500時返回的錯誤,需要添加一些代碼。
首先API初始化時,初始self.exception_handler對象並定義對應的方法添加自定義的錯誤
在handler_request方法進行請求調度時,調度的方法執行邏輯時報500,此時不再默認將錯誤拋出,而是先判斷是否有自定義錯誤處理。
在app.py中,自定義錯誤返回方法,如下。
custom_exception_handler方法只返回自定義的一段話,你完全可以替換成美觀的template。
我們可以實驗性定義一個路由來看效果。
Web服務的中間件也可以理解成鉤子,即在請求前可以對請求做一些處理或者返回Response前對Response做一下處理。
為了支持中間件,在TopWebF目錄下創建middleware.py文件,在編寫代碼前,思考一下如何實現?
回顧一下現在請求的調度邏輯。
1.通過routes裝飾器關聯路由和方法 2.通過API.whitenoise處理 3.如果是請求API介面,那麼會將參數傳遞給API.wsgi_app 4.API.wsgi_app最終會調用API.handle_request方法獲取路由對應的方法並調用該方法執行相應的邏輯
如果希望在request前以及response後做相應的操作,那麼其實就需要讓邏輯在API.handle_request前後執行,看一下代碼。
其中add方法會實例化Middleware對象,該對象會將當前的API類實例包裹起來。
Middleware.handle_request方法其實就是在self.app.handle_request前調用self.process_request方法處理request前的數據以及調用self.process_response處理response後的數據,而核心的調度邏輯,依舊交由API.handle_request方法進行處理。
這里的代碼可能會讓人感到疑惑, __call__ 方法和handle_request方法中都有self.app.handle_request(request),但其調用對象似乎不同?這個問題暫時放一下,先繼續完善代碼,然後再回來解釋。
接著在api.py中為API創建middleware屬性以及添加新中間件的方法。
隨後,在app.py中,自定義一個簡單的中間件,然後調用add_middleware方法將其添加。
定義好中間件後,在請求調度時,就需要使用中間件,為了兼容靜態文件的情況,需要對css、js、ing文件的請求路徑做一下兼容,在其路徑中加上/static前綴
緊接著,修改API的 __call__ ,兼容中間件和靜態文件,代碼如下。
至此,中間件的邏輯就完成了。
但代碼中依舊有疑惑,Middleware類中的 __call__ 方法和handle_request方法其調用的self.app到底是誰?
為了方便理解,這里一步步拆解。
如果沒有添加新的中間件,那麼請求的調度邏輯如下。
在沒有添加中間件的情況下,self.app其實就是API本身,所以 middleware.__call__ 中的self.app.handle_request就是調用API.handle_request。
如果添加了新的中間件,如上述代碼中添加了名為SimpleCustomMiddleware的中間件,此時的請求調度邏輯如下。
因為注冊中間件時,Middleware.add方法替換了原始Middleware實例中的app對象,將其替換成了SimpleCustomMiddleware,而SimpleCustomMiddleware也有app對象,SimpleCustomMiddleware中的app對象,才是API類實例。
在請求調度的過程中,就會觸發Middleware類的handle_request方法,該方法就會執行中間件相應的邏輯去處理request和response中的數據。
當然,你可以通過Middleware.add方法添加多個中間件,這就會構成棧式調用的效果,代碼如下。
啟動web服務後,其執行效果如下。
❺ python ssti之繼承鏈利用
總的來說就是調用python或者框架的內建/全局類,變數,函數獲取敏感信息/執行敏感操作,做題時先明確題目環境再去官方文檔中查找全局變數,類,函數。
返回當前對象實例的類。
返回一個由當前類父類構成的元組,由於python允許多重繼承。
返回一個由當前函數可以訪問到的變數,方法,模塊組成的字典,不包含該函數內聲明的局部變數。
in python2 func.func_globals is func.__globals__
返回一個由當前類的所有子類構成的列表。
python2中形如
的定義不會繼承於object對象,所以不能用__subclasses__()方法,但在python3中即使這樣聲明也會繼承於object。
返回一個由內建函數函數名組成的列表。
返回一個由當前類繼承鏈組成的元組。
返回索引為index的值。
利用字元串,列表,元組,字典,集合等基本對象獲取類,通過類獲取基本類object,通過object獲取敏感類對象。
創建file對象後以可通過read()/write()函數進行文件讀寫。
在 object.__subclasses__()[59/139].__init__.__globals__['__builtins__'] 下儲存了一些函數可供調用。
既然可以使用if語句,同樣也可以使用類似盲注的方式,逐字爆破。
過濾了括弧,沒法用__subclassess__獲取子類,並且config和self置空。查看 flask文檔
flask為jinja2模板提供了兩個函數get_flashed_messages()和url_for(),選擇任意一個函數,構造payload
http://domainname/shrine/{{url_for.__globals__}}
提交後看到回顯里有一個current_app屬性,構造payload
http://domainname/shrine/{{url_for.__globals__.current_app.config}} 或者 http://domainname/shrine/{{url_for.__globals__.['current_app']['config']}}
即可獲取flag
給出一個ctftime上的wp
這個wp中的payload很長是因為search函數進行了深度優先搜索,利用request作為起點的payload也可以簡化為
request._get_data_for_json.__globals__['current_app'].config['FLAG'] 。總之就是通過__globals__獲取全局變數。