Flask 掃盲系列-Flask 上下文

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

請求上下文

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

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

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

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

從上面的代碼咱們能夠想象獲得,request 變量當中應該是包含了本次 HTTP 請求中的相關信息,好比 form 屬性中就是前端提交的表單數據,固然還有些其餘屬性和方法,我整理以下: URL 信息相關,例如請求 URL 爲:www.luobodazahui.top/hello?name=…bootstrap

屬性
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 兩個請求上下文,在當前網站的基礎上,來動手實現一個簡單的認證功能。bash

功能需求整理

咱們當前網站的股票歷史數據查詢時間是能夠自行定義的,那麼咱們能夠增長一個限制,就是非登錄用戶只能夠查詢30天之內的數據,而對於已經登錄的用戶,則不受該限制約束。cookie

那麼咱們就須要一個簡單的登錄頁面,進行登錄操做,固然最重要的就是應用 session 這個請求上下文來判斷用戶登錄狀態了。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/', methods=['GET', '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 了。而這種特性每每和請求鉤子相結合使用,能夠極大的提升代碼的簡潔性。

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

相關文章
相關標籤/搜索