1. 程式人生 > 程式設計 >Flask 掃盲系列-Flask 上下文

Flask 掃盲系列-Flask 上下文

上一次我們做了一個簡單的線上股票走勢網站,今天我們來繼續完善下網站功能,並學習些新的 Flask 知識點。

請求上下文

我們先來看下上一篇中獲取表單的寫法

stock_name = request.form.get('stockName')
query_time = request.form.get('queryTime')
複製程式碼

這裡用到了 request,其實它就是一種請求上下文。

那麼什麼是請求上下文呢,其實就是當 Flask 程式初始化成功後,每次請求中的全域性變數。請求上下文總共有兩個,request 和 session。

從上面的程式碼我們可以想象得到,request 變數當中應該是包含了本次 HTTP 請求中的相關資訊,比如 form 屬性中就是前端提交的表單資料,當然還有些其他屬性和方法,我整理如下: URL 資訊相關,例如請求 URL 為:

www.luobodazahui.top/hello?name=…

屬性
path '/hello'
full_path '/hello?name=zhouluobo'
host 'www.luobodazahui.top'
host_url 'www.luobodazahui.top'
base_url 'www.luobodazahui.top/hello'
url 'www.luobodazahui.top/hello?name=…'

報文相關資訊

屬性或方法 說明
args 查詢字串資訊
cookies cookies 資訊字典
data 字串形式的請求資料
form 表單資料
get_json() 獲取 json 型別的請求資料
method 請求的 HTTP 方法

那麼 session 呢,其實就是用於儲存請求之間需要保留的資料,比較典型的應用場景就是使用者的認證功能。

下面我們就結合 request 和 session 兩個請求上下文,在當前網站的基礎上,來動手實現一個簡單的認證功能。

功能需求整理

我們當前網站的股票歷史資料查詢時間是可以自行定義的,那麼我們可以增加一個限制,就是非登陸使用者只可以查詢30天以內的資料,而對於已經登陸的使用者,則不受該限制約束。

那麼我們就需要一個簡單的登陸頁面,進行登陸操作,當然最重要的就是應用 session 這個請求上下文來判斷使用者登陸狀態了。

功能實現

判斷查詢時間

首先先實現功能限制處理,把未登陸使用者輸入大於30天的請求攔截,並提示需要登陸後再嘗試

修改 get_kline_chart() 函式,增加一個判斷,如果 query_time 大於30,則返回403響應碼

@app.route("/Kline",methods=['GET','POST'])
def get_kline_chart():
    stock_name = request.form.get('stockName')
    query_time = request.form.get('queryTime')
    if int(query_time) > 30:
        abort(403)
...
複製程式碼

再修改 JQuery 的 getData 函式中的異常部分

error: function(err) {
                    if (err.status === 403) {
                        alert("請先登陸系統!");
                    }
                    else {
                        alert("錯誤的股票程式碼!");
                    }
                }
複製程式碼

新增登陸入口

接下來就來新增登陸入口,首先在導航欄上新增一個登陸的連結

<ul class="nav navbar-nav navbar-right">
                <li><a href="{{ url_for('login') }}">Log In</a></li>
                <li><a href="{{ url_for('logout') }}">Log Out</a></li>
            </ul>
複製程式碼

兩個連結分別對應到登陸和登出的檢視函式

建立登陸登出函式,應用 session 變數來傳遞使用者狀態

@app.route('/login/')
def login():
    session['login_user'] = 'admin'
    return redirect(url_for('index'))


@app.route('/logout')
def logout():
    if 'login_user' in session:
        session.pop('login_user')
    return redirect(url_for('index'))
複製程式碼

此時我們重新整理頁面,檢視當前的頁面展示

可以看到無論使用者登陸與否,都會展示 login 和 logout 兩個按鈕,這很不美觀,我們再做下修改

<ul class="nav navbar-nav navbar-right">
                {% if not auth %}
                <li><a href="{{ url_for('login') }}">Log In</a></li>
                {% else %}
                <li><a href="{{ url_for('logout') }}">Log Out</a></li>
                {% endif %}
            </ul>
複製程式碼

做一個判斷,如果 auth 是 False 時,展示 Login In,如果是 True 時,展示 Log Out。

再修改 index 檢視函式,判斷使用者狀態,並返回 auth 變數到模板

@app.route("/")
def index():
    auth = False
    if 'login_user' in session:
        auth = True
    return render_template("index.html",auth=auth)
複製程式碼

新增登陸表單

當前的登陸是直接寫入 cookie 的,並沒有使用者輸入表單的登陸過程,現在完成這個過程。

我們使用 Flask-WTF 來快速建立表單

from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import DataRequired

class LoginForm(FlaskForm):
    name = StringField('name',validators=[DataRequired()])
    password = PasswordField('password',validators=[DataRequired()])
    submit = SubmitField('Submit')
複製程式碼

接下來我們建立一個 login.html 檔案,並把表單渲染成 HTML

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block title %}登陸{% endblock %}


{% block page_content %}
{{ wtf.quick_form(form) }}
{% endblock %}
複製程式碼

接下來我們修改 login 檢視函式,接收表單資料,並驗證使用者

def check_name(name,password):
    return True


@app.route('/login/','POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        name = form.name.data
        password = form.password.data
        if check_name(name,password):
            session['login_user'] = 'admin'
            return redirect(url_for('index'))
    return render_template('login.html',form=form)
複製程式碼

這裡的驗證使用者函式我沒有做任何邏輯,所以無論輸入什麼使用者名稱和密碼,都會驗證通過並登陸成功。

驗證使用者

最後一步,我們就可以在 get_kline_chart 函式中驗證當前使用者是否已經登陸過了,如果是,則正常操作

    if int(query_time) > 30:
        if 'login_user' in session:
            pass
        else:
            abort(403)
複製程式碼

至此,我們就完成了基於請求上下文 session 的簡單認證功能。

現在我們再來回顧下 session 上下文到底為我們做了些什麼

  1. 設定 cookie,用於傳遞資訊
  2. 自動加密,加大篡改難度

當我們完成登陸操作後,可以檢視瀏覽器中的 cookie 資訊,可以發現我們通過 session 設定的 cookie 資訊已經被加密了,這極大的提高了我們應用的安全性

而這個加密的 key,我們可以通過初始化的 app 的方法來設定

app.secret_key = 'A Hard String'
複製程式碼

程式上下文

接下來我們再來看看另一種 Flask 上下文--程式上下文。程式上下文主要包含兩種,current_app 和 g,current_app 就是當前的程式例項,而 g 則可以臨時儲存當前請求的資料,方便使用。

current_app

對於 current_app 這個程式上下文,主要的用途在於當程式當中存在多個程式例項時,使用該上下文可以方便的獲取到當前的程式例項,一般在編寫大型應用時會用到,我們在後面的學習中用到時再詳細介紹。

g

對於 g 這個上下文變數來說,其用途會更加廣泛些。比如說如果對於某個請求,我們幾個檢視函式都需要用到一個前端傳遞過來的變數,那麼就可以把它儲存到 g 變數當中

g.name = request.args.get('name')
複製程式碼

這樣,其他的檢視函式就可以在同一個請求中直接使用 g.name 來訪問,而不用每次都呼叫 request 了。而這種特性往往和請求鉤子相結合使用,可以極大的提高程式碼的簡潔性。

嗯,好的,今天的分享就到這裡了,我們下次再見!